How to remove child items correctly

Discussion of open issues, suggestions and bugs regarding LinqConnect – Devart's LINQ to SQL compatible ORM
Post Reply
OSTGerman
Posts: 5
Joined: Tue 13 Dec 2011 13:47

How to remove child items correctly

Post by OSTGerman » Tue 13 Dec 2011 14:44

I have a foollowing scenario: there is entity A and entity B, that is "child" of A (one-to-many relationship). User selects an instance of A with the given id from DB, makes a copy of it and copies of all connected B instances. After that some children of type B are marked as removed, and DeleteAllOnSubmit() is called to notify data context.

Code: Select all

var context = new MyDataContext();
var a1 = context.A.First(item => item.Id == 1);
var a2 = new A();
a2.Name = a1.Name;
a2.A1 = a1;
a2.ParentId = a1.Id;
foreach (var b1 in a1.Bs)
{
    var b2 = new B();
    b2.Value = b1.Value;
    b2.A = a2;
    a2.Bs.Add(b2);
}
/* Here user decides to delete some of a2's children of type B, and all removed items are placed into var IList deletedItems */

context.B.DeleteAllOnSubmit(deletedItems);
context.SubmitChanges();

After SubmitChanges() all entities, even the "deleted" ones appear to be in the DB. Following code would throw an exception "Cannot remove an entity that has not been attached":

Code: Select all

foreach (var b in deletedItems)
{
    a2.Remove(b);
}
If I don't make a copy of a1 instance and just modify it the same way, everything works as expected. Note, that I never call InsertOnSubmit() for newly created instances. I imagine, that all the "magic" is done through

Code: Select all

a2.A1 = a1;
But if I call InsertOnSubmit() for newly created A and B instances, nothing changes.

So how could I achieve the desired functionality? Or am I doing something wrong?

I use LinqConnect with DotConnect for Oracle 6.60 Professional (Trial version).

StanislavK
Devart Team
Posts: 1710
Joined: Thu 03 Dec 2009 10:48

Post by StanislavK » Wed 14 Dec 2011 16:39

Thank you for the report, we have reproduced these problems. We will analyze them and inform you about the results.

As a temporary workaround, you can remove the dependent entities (i.e., 'b' from the 'deletedItems' collection) instead of deleting them from the corresponding table. As they were attached to the context just because of being associated with the entity already attached ('a2'), removing them from 'a2.Bs' should cancel insertion. Please tell us if this helps.

OSTGerman
Posts: 5
Joined: Tue 13 Dec 2011 13:47

Post by OSTGerman » Thu 15 Dec 2011 07:10

Thank you for your reply. I've already tried to remove the child items from parent's collection, but following code

Code: Select all

foreach (var b in deletedItems)
{
    a2.Bs.Remove(b);
} 
would throw an exception "Cannot remove an entity that has not been attached"

StanislavK
Devart Team
Posts: 1710
Joined: Thu 03 Dec 2009 10:48

Post by StanislavK » Thu 15 Dec 2011 16:19

Please specify whether you are removing the entities from the collection and deleting them from the table, or doing only the first operation. In our environment, the second option works, whereas the first one doesn't. I.e., the code

Code: Select all

context.B.DeleteAllOnSubmit(deletedItems);
foreach (var b in deletedItems)
  a2.Remove(b);
context.SubmitChanges();
throws the "Cannot remove an entity that has not been attached" exception, and this one results in cancelling inserts of 'deletedItems':

Code: Select all

foreach (var b in deletedItems)
  a2.Remove(b);
context.SubmitChanges();
If the second code sample causes an error in your environment, could you please send us a small sample with which this error can be reproduced?

OSTGerman
Posts: 5
Joined: Tue 13 Dec 2011 13:47

Post by OSTGerman » Fri 16 Dec 2011 12:52

I think I partially solved the problem. My object graph is rather complicated and contains not only A and B, but also C, which is parent of B. And to cancel insertion of B entities i must call a.Bs.Remove(b) and c.Bs.Remove(b).

Moreover, in my real-world application there are entities of type D, that are children of B. They are copied, too. To prevent them from being inserted I also must call b.Ds.Remove(d), despite of the fact that "Delete Rule" for this relationship is set to cascade. I find it hard to mantain code as number of entities and relations between them in my project grows.

In my point of view, the single DeleteOnSubmit() call should cancel insertion of corresponding entity and all it's children.
Would this approach be implemented in future versions?

StanislavK
Devart Team
Posts: 1710
Joined: Thu 03 Dec 2009 10:48

Post by StanislavK » Fri 16 Dec 2011 15:31

Thank you for the clarification. We are currently working on the LinqConnect change tracking functionality, so this and related problems should be fixed in one of the nearest versions. We will post here when this version is released.

Post Reply