AnantLabs / codesmith

Automatically exported from code.google.com/p/codesmith
1 stars 0 forks source link

One-to-Many or Many-to-Many relationship does not work perfectly when dealing with more than one child record #478

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Two situations:
   a. From a parent object, say parent, add/delete a few new children:
       theParent.Children.add(newChild1)
       theParent.Children.add(newChild2)
       theParent.Children.add(newChild3)
       theParent.Children.remove(newChildren3)
       _datacontext.SubmitChanges()

   b. From a parent, delete some existing children
       theParent.Children.Remove(existingChild1)
       theParent.Children.Remove(existingChild2)
       theParent.Children.Remove(existingChild3)
       _datacontext.SubmitChanges()

   then The error occurs normally:
   System.ArgumentException: An item with the same key has already been added.
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at System.Data.Linq.ChangeProcessor.EdgeMap.Add(MetaAssociation assoc, TrackedObject from, TrackedObject to)
   at System.Data.Linq.ChangeProcessor.BuildEdgeMaps()
   at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
   at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)

2. This error occurs for normal linq as well, but there is a workaround:
    For Plinqo, 
        set "IncludeDeleteOnNull" = True in the CSP file
    For normal Linq, 
        Set the "DeleteOnNull" = true in the DBML file

    And then do the following: 
        call tblChild.InsertOnSubmit(anyChild) before theParent.Children.Add(anyChild)
        call tblChild.DeleteOnSubmit(anyChild) before theParent.Children.Remove(anyChild)

3. However, the ISSUE is this workaround only works for normal Linq, but NOT 
Plinqo. 
Plinqo works fine with just single child record, but for adding/removing 
multiple child records within one transaction, it has the above error.

What is the expected output? What do you see instead?
It should perform insert/delete multiple records same as normal Linq

I have tested Plinqo 4 and 5, but same errors. 

I have attached two test projects (one for Linq, one for PLinqo 5), they are 
doing exactly the same thing, yet PLinqo gives error while Linq does not. 

Please respond as soon as possible.
Thank you

Original issue reported on code.google.com by rex.liuz...@gmail.com on 5 Aug 2010 at 9:09

Attachments:

GoogleCodeExporter commented 9 years ago
One thing worth to mention:
In the .Generated.vb class (for example, UserRole.Generated.vb in the 
TestPlinqo5 project), in the "Association Mapped Properties" region, if we 
change the IsUnique:=False Manualy (default True), it works as expected. 
However, we don't know how to config the csp file to make this happen, and also 
what is the impact if we change the value to "False"

I think this issue is quite similar to 
issue 314 (http://code.google.com/p/codesmith/issues/detail?id=314)
and
issue 32 (http://code.google.com/p/codesmith/issues/detail?id=32)
Yet they were not solved at all but closed...

Please help as we really got stucked.

Original comment by rex.liuz...@gmail.com on 5 Aug 2010 at 9:30

GoogleCodeExporter commented 9 years ago
Issue 477 has been merged into this issue.

Original comment by bniemyjski on 5 Aug 2010 at 3:12

GoogleCodeExporter commented 9 years ago
We will look into this issue and see what we can do.  It may be something 
outside of our control.

Original comment by e...@ericjsmith.com on 5 Aug 2010 at 4:01

GoogleCodeExporter commented 9 years ago
Hi there, 

Is there any investigation result so far? 

We have used CodeSmith and PLinqo to generate our Business Object layer, 
however, now we are really stuck by the above mentioned issue. we are unable to 
use the one-to-many or many-to-many relationship to handle adding/deleting 
child records within one transaction. 

And unluckily, it is unacceptable that we manage only one child relation within 
one transaction because the transaction volume will not be managable.

Our system has a very complex database structure and we have to use the 
one-to-many or many-to-many relationship almost everywhere. So please let us 
know as soon as possible whether PLinqo can handle it, so if not, we still have 
enough time to seek other approaches.

Best Regards
Rex

Original comment by rex.liuz...@gmail.com on 12 Aug 2010 at 7:55

GoogleCodeExporter commented 9 years ago

Original comment by bniemyjski on 13 Aug 2010 at 12:36

GoogleCodeExporter commented 9 years ago
Hello,

I looked into this issue as well as other issues and it is a design flaw in 
Linq-To-SQL. There is no way for us to hack around the limitation that you can 
only call remove once per submit changes on an association. If you take a look 
at the following code in reflector: 

   at System.Data.Linq.ChangeProcessor.EdgeMap.Add(MetaAssociation assoc, TrackedObject from, TrackedObject to)
   at System.Data.Linq.ChangeProcessor.BuildEdgeMaps()
   at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
   at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)

You will see why this is not possible.

There are two solutions to this that will resolve this issue.

The first one being you can delete using the join table like this

_dbc.UserRole.DeleteOnSubmit(userRole_1) 'Trick to perform DeleteOnSubmit 
beforehand
_dbc.UserRole.DeleteOnSubmit(userRole_2)
_dbc.SubmitChanges()

then make a database call to refresh the current user entity. I know that this 
is not optimal, but there is no way around this issue (thank Microsoft).

The other way you could do this is to call Delete twice like this:

currentUser.UserRoleList.Remove(userRole_1)
_dbc.SubmitChanges()
currentUser.UserRoleList.Remove(userRole_2)
_dbc.SubmitChanges()

I think that the first approach would be better unless your object graph for 
the entity in question is large and you are not needing to use the instance 
after the remove. As I was taking a look in the SQL Profiler and each remove 
makes two database calls to the server.

I'm marking this as under consideration as we would really like to fix this 
issue, but as currently there is no way for us to override Microsoft's 
implementation.

Please let us know if you have any questions as we would be more than happy to 
explain anything or help you as much as we can.

Thanks
-Blake Niemyjski

Original comment by bniemyjski on 13 Aug 2010 at 2:05

GoogleCodeExporter commented 9 years ago
The reflection did show that it was some exception thrown by Microsoft Linq, 
however, the problem is, why the workaround works for Microsoft Linq (as shown 
in the test project I created for Linq in the attachment), while it has problem 
with PLinqo. And the two simple projects do the same thing exactly...

And even wired, why it works fine if we simply manually set the "IsUnique" to 
false in the generated class? So I suspect that PLinqo called some method 
internally in the method currentUser.UserRoleList.Remove(userRole_1), which 
triggers some actions that caused the problem. 

We have a lot of delete/add/edit the associations for the association objects. 
It is not acceptable to fire one DB call for each delete action. And it is not 
possible we refresh particular table/objects after one deletion as that loses 
the point to use the relationship management and might also cause some 
in-consistency. 

So now my question is: What is the purpose to put the attribute of "IsUnique" 
for reference property for PLinqo? It seems this attribute is only for the 
parent reference property within the child object, which actually definately 
UNIQUE to the child object. Is it possible to get rid of this attribute or how 
can we configure the CSP file to make the "IsUnique" to false automatically? 
And what is the impact if we do so, for example, whether it will cause some 
other problems? 

By comparing the two projects for Linq and PLinqo, we believe that this problem 
is caused by PLinqo itself, although the relationship management is one of the 
most selling points of Plinqo.

Best Regards
Rex

Original comment by rex.liuz...@gmail.com on 14 Aug 2010 at 6:00

GoogleCodeExporter commented 9 years ago

Original comment by bniemyjski on 16 Aug 2010 at 3:15

GoogleCodeExporter commented 9 years ago
This issue was updated by revision r1908.

- fix issue with "An item with the same key has already been added."

Original comment by paul.wel...@gmail.com on 16 Aug 2010 at 8:57

GoogleCodeExporter commented 9 years ago
Hi Paul,

Thank you so much for your help. I got the template from the SVN and it works 
now. Just check with you, it's still not in the official release yet, right? 

One more thing that needs your advice, for this workaround that we still have 
to do the following: call _dbc.UserRole.InsertOnSubmit(userRole_1) explicitly 
before we call currentUser.UserRoleList.Add(userRole_1), And call 
_dbc.UserRole.DeleteOnSubmit(userRole_3) explicitly before we call 
currentUser.UserRoleList.Remove(userRole_3)

So is it possible that you can make the call to InsertOnSubmit/DeleteOnSubmit 
internally within currentUser.UserRoleList.Add/Remove? which means, this action 
can be triggered automatically and we don't have to keep performing the two 
calls whenever we Add/Delete? As we expected that the 
InsertOnSubmit/DeleteOnSubmit should be automatically triggered whenever we 
add/delete a child to/from parent. 

Please kindly advise. 

And I realized that we are using two threads discussing this issue (other one: 
http://community.codesmithtools.com/Template_Frameworks/f/66/p/11246/42999.aspx)
, which one do you prefer to use as there is no point we post replies at two 
places concurrently. 

Best Regards
Rex

Original comment by rex.liuz...@gmail.com on 17 Aug 2010 at 2:48

GoogleCodeExporter commented 9 years ago
i am Mrs mercy i am hear to give testimony of how i got back my husband, we got 
married for more than 2 years and have gotten two kids. thing were going well 
with us and we are always happy. until one day my husband started to behave in 
a way i could not understand, i was very confused by the way he treat me and 
the kids. later that month he did not come again and he called me that he want 
a divorce, I asked him what have i done wrong to deserve this from him, all he 
was saying that he want a divorce and that he hates me and do not want to see 
me again in his life, i was mad and also frustrated do not know what to do,i 
was sick for more than 2 weeks because of the divorce. i love him so much he 
was everything to me without him my life is incomplete. i told my sister and 
she told me to contact a spell caster, i never believe in all this spell 
casting of a thing. i just
want to try if something will come out of it. I contacted DR. omoba for the 
return of my husband to me, they told me that my husband have been taken by 
another woman that she cast a spell on him that is why he hates me and also 
want us to divorce. then they told me that they have to cast a spell on him 
that will make him return to me and the kids, they cast the spell and after 3 
days my husband called me
and he told me that i should forgive him, he settled to apologize on phone and 
said that he still love me that he did not know what happen to him that he left 
me. it was the spell that the Dr omoba shrine casted on him that made him 
comeback to me today,me and my family are now happy again today. thank you DR. 
omoba for what you have done for me i would have been nothing today if not for 
your great spell. i want
you my friends who are passing through this kind of love problem of getting 
back their husband, wife , or ex boyfriend and girlfriend to contact 
dromobaspellhome@gmail.com and you will see that your problem will be solved.

Original comment by kenkenil...@gmail.com on 31 Jul 2013 at 10:05