Acumatica REST API INTran - rest

I have a Generic Inquiry and Endpoint to get all rows and fields of INTran, which works fine.
What fields in an INTran row are it's unique keys?
I am populating a DB on a different server with this data, so I can do some detailed analysis.
I am using the LastModified field to get updates, and I need to setup my local DB keys so the correct row will be updated, and a new row will not be inserted (unless its keys are new).
I do not have login access to the Acumatica server, so I have to do this through the API.
Version 2019R1

If you have access to the Acumatica website you can look up the INTran DAC (class INTran) with the Source Code page SM204570.
The DAC indicates primary keys are fields:
INTran.DocType
INTran.RefNbr
INTran.LineNbr
You can also deduce the DB type and length in the DAC attribute from the same INTran DAC.
Example DocType, PXDBString with IsFixed of length 1 maps to DB type char(1) :
#region DocType
public abstract class docType : PX.Data.BQL.BqlString.Field<docType> { }
protected String _DocType;
[PXUIField(DisplayName = INRegister.docType.DisplayName)]
[PXDBString(1, IsFixed = true, IsKey = true)]
[PXDefault(typeof(INRegister.docType))]
[INDocType.List()]
public virtual String DocType
{
get { return this._DocType; }
set { this._DocType = value; }
}
#endregion
PXDBString without IsFixed maps to varchar type.
PXDBString with IsUnicode maps to nvarchar.
PXDBInt maps to int.
DAC attributes should always match the DB type but DB is the final source of truth.
In DB here's how those fields are declared:
[DocType] [char](1) NOT NULL
[RefNbr] [nvarchar](15) NOT NULL
[LineNbr] [int] NOT NULL

Related

In EF 6 DBInterception, how to get the actual value from DbModificationClause clause?

I'm researching with encrypting an EF 6 db column using db interceptors and custom annotation on the ef entity: https://www.codeguru.com/csharp/soft-deleting-entities-cleanly-using-entity-framework-6-interceptors/
However, the guide's example is using a static string to replace the value prior to inserting to the database. I need the original value to encrypt it and then use the new encrypted value to be inserted to the db but I can't seem to figure out how to get the original value.
public static DbModificationClause UpdateIfMatch(this DbModificationClause clause, string property)
{
var propertyExpression = (DbPropertyExpression)((DbSetClause)clause).Property;
// Get the original value to be inserted to the DB
// Encrypt that value and use it instead
var newEncryptedValue = propertyExpression.GetValue()?
if (propertyExpression.Property.Name == property)
{
return DbExpressionBuilder.SetClause(propertyExpression, DbExpression.FromString(newEncryptedValue));
}
return clause;
}

what is the guid-like id associated with a dynamic proxy in Entity Framework?

I'm trying to figure out an exception, and wondering how the id for an Entity object is generated:
System.Data.Entity.DynamicProxies.TaskInstance_EFB25059687D16F3AB6ABF93C582495406916AC2CC28E7E312CB6B50EC3CF7A5.get_TaskLogs()
TaskInstance is the Entity here. It has the same identifier every time the exception happens. Just wondering how it works underneath.
Somehwere in EF's code base concerning proxy type generation, there is this method ...
// <summary>
// Creates an SHA256 hash of a description of all the metadata relevant to the creation of a proxy type
// for this entity type.
// </summary>
private string BuildEntityTypeHash()
{
using (var sha256HashAlgorithm = MetadataHelper.CreateSHA256HashAlgorithm())
{
var hash = sha256HashAlgorithm.ComputeHash(Encoding.ASCII.GetBytes(BuildEntityTypeDescription()));
// convert num bytes to num hex digits
var builder = new StringBuilder(hash.Length * 2);
foreach (var bite in hash)
{
builder.Append(bite.ToString("X2", CultureInfo.InvariantCulture));
}
return builder.ToString();
}
}
... where BuildEntityTypeDescription() is a method that builds a string from the type's navigation properties, key members etc.
So, basically, the proxy type name is a hashed representation of the type's meta data, so it will always be the same string as long as the type doesn't change.

Saving a Hashtable using Mongo & the Play framework?

I've got a model defined like the following...
#MongoEntity
public class Ent extends MongoModel{
public Hashtable<Integer, CustomType> fil;
public int ID;
public Ent(){
fil = new Hashtable<Integer, CustomType>();
}
}
CustomType is a datatype I've created which basically holds a list of items (among other things). At some point in my web application I update the hashtable from a controller and then read back the size of the item I just updated. Like the following...
public static void addToHash(CustomType type, int ID, int key){
//First I add an element to the list I'm storing in custom type.
Ent ent = Ent.find("byID",ID).first();
CustomType element = user.fil.get(key);
if(element == null) element = new CustomType();
element.add(type);
ent.save();
//Next I reset the variables and read back the value I just stored..
ent = null;
ent = User.find("byID",ID).first();
element = ent.fil.get(ID);
System.out.println("SIZE = " + element.size()); //null pointer here
}
As you can see by my above example I add the element, save the model and then attempt to read back what I have just added and it has not been saved. The above model Ent is a minimal version of the entire Model I'm actually using. All other values in the model including List's, String's, Integer's etc. update correctly when they're updated but this Hashtable I'm storing isn't. Why would this be happening and how could I correct it?
You should probably post on the play framework forum for better help..
Alternatives for a mongodb framework are morphia and springdata which have good documentation.
Not sure how Play maps a hash table to a document value, but it seems it cannot update just the hash table using a mongo operator.
You should be able to mark the whole document for update which would work but slower.

Code First Entity Framework

We are using Miscrosoft's code first entity framework (4.1) to map to an existing database. We want to be able to change the datatypes and values of some properties that map one to one with a table. For instance, there is a column on the table that determines if a record is current. It is an integer column, and has values 1 or 2. We don't want to change the database as there are many different applications fetching data from that colum, but it would be nice for our code to have the class that maps to that table have a bool property that is IsActive, which returns true if the table column is 1 and false otherwise. Is there a way to configure the EnityFrame work so that we can define this mapping directly without having two properties on the actual class, one for the integer column (mapped to the database) and one boolean property computed from the other? Can I map the boolean property directly to the integer column?
Simple answer is no. EF is totally stupid in this area and it is completely missing simple type mapping.
That means that you cannot change type of scalar properties and your class indeed has to work with that int property using values 1 and 2 to define your IsActive.
The workaround can be:
public class YourClass
{
public int IsActiveValue { get; set; }
[NotMapped]
public bool IsActive
{
get { return IsActiveValue == 2; }
set { IsActiveValue = value ? 2 : 1; }
}
}
This workaround has some disadvantages
You must have two properties and IsActvieValue must be visible to context
You cannot use IsActive in linq-to-entities queries

Entity Framework - trying to insert null values when creating a new object

I'm having the same problem that a few of you have had - when trying to insert a new object, EF inserts null values for some of their properties, and the insert fails.
First let me describe the structure of our DB. Its an event management system, in which each event needs to be associated with a practice group, stored in a cache table but ultimately fetched from Active Directory. I manually created the join table - is that a problem? Anyway, so Event has a foreign key pointing to EventPracticeGroup, which has a foreign key pointing to PracticeGroupCache. PracticeGroupCache also has a RegionId pointing to the Regions table.
The problem comes when trying to insert a new EventPracticeGroup object. Below is the code I'm currently using:
var eventPracticeGroup = new EventPracticeGroup();
if (TryUpdateModel<EventPracticeGroup>(eventPracticeGroup))
{
/*
var eventId = EventScheduleRepository.GetById(Convert.ToInt32(Request.QueryString["EventScheduleId"])).EventId;
eventPracticeGroup.Event = EventRepository.GetById(eventId);
eventPracticeGroup.PracticeGroupCache = PracticeGroupCacheRepository.GetById(eventPracticeGroup.PracticeGroupCacheId);
eventPracticeGroup.PracticeGroupCache.Region = RegionRepository.GetById(eventPracticeGroup.PracticeGroupCache.RegionId);
EventPracticeGroupRepository.Add(eventPracticeGroup);
*/
var eventId = EventScheduleRepository.GetById(Convert.ToInt32(Request.QueryString["EventScheduleId"])).EventId;
var theEvent = new Event() { Id = eventId };
EventRepository.Repository.UnitOfWork.Context.AttachTo("Events",theEvent);
var practiceGroupCache = new PracticeGroupCache() { Id = eventPracticeGroup.PracticeGroupCacheId };
practiceGroupCache.Region = new Region() { Id = eventPracticeGroup.PracticeGroupCache.RegionId };
eventPracticeGroup.PracticeGroupCache = practiceGroupCache;
EventPracticeGroupRepository.Add(eventPracticeGroup);
EventPracticeGroupRepository.Save();
return RedirectToAction("Index");
}
Anyway... as you can see, I've just tried using stub objects (no help), and I've also tried actually fetching and setting the objects. The error I get is:
Cannot insert the value NULL into column 'Name', table 'XXXX.dbo.Regions'; column does not allow nulls. INSERT fails. The statement has been terminated.
Obviously name is not a key field. I have checked the EDMX XML - only the Id (primary key columns) have StoreGeneratedPattern set to Identity, as they should (they are int32 identity columns). Not a single foreign key has StoreGeneratedPattern set to identity.
if I set Regions.Name to allow nulls, PracticeGroupCaches.Description throws the same error. It seems that every linked object gets set to null. I did have a look with the debugger, when I used the now commented out code, nothing was null and everything had a value. I even got the RegionRepository to return all of the regions, just to see if one of them somewhere had a null name. None did. There are only 2 in my test DB. Our object context is shared per HTTP request.
Please can anyone help. At this point I would settle for using the dirtiest workaround as long as it worked.
Regards,
Jonathan.
Look what happens when you call this line:
EventPracticeGroupRepository.Add(eventPracticeGroup);
You are adding a new eventPracticeGroup to the context. But eventPracticeGroup has the other related objects:
eventPracticeGroup -> PracticeGroupCache -> Region
And you create new objects for those:
var practiceGroupCache = new PracticeGroupCache() {
Id = eventPracticeGroup.PracticeGroupCacheId };
practiceGroupCache.Region = new Region() {
Id = eventPracticeGroup.PracticeGroupCache.RegionId };
eventPracticeGroup.PracticeGroupCache = practiceGroupCache;
When you add the eventPracticeGroup to the context this whole object graph gets added which means that EF considers all three objects as new which have to be added to the DB. Since you only fill the Id properties other string properties (like Name or Description) are null. Because they are not nullable in the database the INSERT command fails.
But I guess that you don't want to insert the related entities into the DB anyway but only the eventPracticeGroup. So you need to attach them to the context before you add the new object, something like:
var practiceGroupCache = new PracticeGroupCache() {
Id = eventPracticeGroup.PracticeGroupCacheId };
EventRepository.Repository.UnitOfWork.Context.AttachTo(
"PracticeGroupCaches",practiceGroupCache);
practiceGroupCache.Region = new Region() {
Id = eventPracticeGroup.PracticeGroupCache.RegionId };
EventRepository.Repository.UnitOfWork.Context.AttachTo(
"Regions",practiceGroupCache.Region);
eventPracticeGroup.PracticeGroupCache = practiceGroupCache;
EventPracticeGroupRepository.Add(eventPracticeGroup);
BTW as a side note: About this EventRepository.Repository.UnitOfWork.Context.XXX take a look at Ladislav Mrnka's answer here: EF 4.0 IsAttachedTo extension method and error An object with the same key already exists
Try to Add: [DatabaseGenerated(DatabaseGeneratedOption.None)]
On your Id field, Like:
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
It seems like you already found the problem and the solution. In your DB schema it seems like the columns don't allow NULL values. So either change all these columns to allow NULL or don't insert null (this is what you currently are trying to do)