Why Is Activerecord Not Smart Enough to Know That the Object_Id of the Father Should Be Equal to the Object_Id of the Parent of Its Children

create object parent which nested children in mongoose

Did you try populate?

Here is a simple example:

Parent.find().populate("children").exec(...)

As long as you specify the children's ref to a model, mongoose is smart enough to join the children with the parents.

Insert to Parent and child custom object using external Id

Ext. ids are meant to be used in integrations, Data Loader... They can be used in Apex too but the syntax looks bit funny. Use them in Apex if you must save on queries or want to go "dear salesforce, I don't remember if I saved this object already, I know unique identifier is 123, go figure it out yourself whether it needs insert or update".

If you insert parent and child in same transaction - just user the Id generated into parent record. If they're separate, a while ago you did this:

insert new sumchans__City_Master__c city = new sumchans__City_Master__c(Name=Vancouver',
sumchans__PROVINCE__c = 'BC',
sumchans__City_Name_Ext_Id__c = 'Vancouver'
);

Then later in another transaction you can do this without querying:

sumchans__City_Stat__c cityStat = new sumchans__City_Stat__c(Name = 'Vancouver', 
sumchans__ON_BILLINGS__c = 50,
sumchans__City_Master__r = new sumchans__City_Master__c(
sumchans__City_Name_Ext_Id__c='Vancouver'
)
);
insert cityStat;

Note that I used __r instead of __c. __c would be your real foreign key, Id field, 15 or 18 characters. __r would be a reference to another object (with ext. id or query result for example), similar to writing SELECT FirstName, Email, Account.Name FROM Contact.

In Apex it has to be as a object referece (so either query or cheat with new keyword, just to create it in memory. You won't actually save that "parent"). In things like data loader you can map values bit like myCsvExtIdColumn -> sumchans__City_Master__r.sumchans__City_Name_Ext_Id__c

The relationship could not be changed because one or more of the foreign-key properties is non-nullable

You should delete old child items thisParent.ChildItems one by one manually. Entity Framework doesn't do that for you. It finally cannot decide what you want to do with the old child items - if you want to throw them away or if you want to keep and assign them to other parent entities. You must tell Entity Framework your decision. But one of these two decisions you HAVE to make since the child entities cannot live alone without a reference to any parent in the database (due to the foreign key constraint). That's basically what the exception says.

Edit

What I would do if child items could be added, updated and deleted:

public void UpdateEntity(ParentItem parent)
{
// Load original parent including the child item collection
var originalParent = _dbContext.ParentItems
.Where(p => p.ID == parent.ID)
.Include(p => p.ChildItems)
.SingleOrDefault();
// We assume that the parent is still in the DB and don't check for null

// Update scalar properties of parent,
// can be omitted if we don't expect changes of the scalar properties
var parentEntry = _dbContext.Entry(originalParent);
parentEntry.CurrentValues.SetValues(parent);

foreach (var childItem in parent.ChildItems)
{
var originalChildItem = originalParent.ChildItems
.Where(c => c.ID == childItem.ID && c.ID != 0)
.SingleOrDefault();
// Is original child item with same ID in DB?
if (originalChildItem != null)
{
// Yes -> Update scalar properties of child item
var childEntry = _dbContext.Entry(originalChildItem);
childEntry.CurrentValues.SetValues(childItem);
}
else
{
// No -> It's a new child item -> Insert
childItem.ID = 0;
originalParent.ChildItems.Add(childItem);
}
}

// Don't consider the child items we have just added above.
// (We need to make a copy of the list by using .ToList() because
// _dbContext.ChildItems.Remove in this loop does not only delete
// from the context but also from the child collection. Without making
// the copy we would modify the collection we are just interating
// through - which is forbidden and would lead to an exception.)
foreach (var originalChildItem in
originalParent.ChildItems.Where(c => c.ID != 0).ToList())
{
// Are there child items in the DB which are NOT in the
// new child item collection anymore?
if (!parent.ChildItems.Any(c => c.ID == originalChildItem.ID))
// Yes -> It's a deleted child item -> Delete
_dbContext.ChildItems.Remove(originalChildItem);
}

_dbContext.SaveChanges();
}

Note: This is not tested. It's assuming that the child item collection is of type ICollection. (I usually have IList and then the code looks a bit different.) I've also stripped away all repository abstractions to keep it simple.

I don't know if that is a good solution, but I believe that some kind of hard work along these lines must be done to take care of all kinds of changes in the navigation collection. I would also be happy to see an easier way of doing it.



Related Topics



Leave a reply



Submit