I care... :-D

Giacomo

On Thu, May 14, 2009 at 5:40 AM, Jonathan Pryor <[email protected]> wrote:

>  For those that care, this has been fixed in r1073 (along with the longest
> commit message in project history).
>
> - Jon
>
>
> On Mon, 2009-05-11 at 17:18 -0400, Jonathan Pryor wrote:
>
> Attached is my current patch to make this work.  It doesn't work.
>
> The approach looks at all properties of the object we're
> inserting/updating, looking for EntitySet<T>'s, and if any are found it
> then inserts/updates the items found within the EntitySet<T>'s.  This
> appears to work properly.
>
> The current problem is that after the Category is inserted,
> Category.CategoryID is updated.  However, the Product doesn't see the new
> CategoryID value, so it tries to insert using 0 as the CategoryID, which
> fails due to a Foreign Key constraint violation.
>
> What I'm currently wondering is how the Products attached to the Categoryare 
> notified that the
> CategoryID has changed.  The DbLinq-generated Category and Product classes
> seem to be similar enough, and INotifyPropertyChanged/etc. aren't used
> within the file, so I'm not sure what mechanism is used to update all
> Products attached to the Category.
>
> Thoughts?
> - Jon
>
> On Mon, 2009-05-11 at 20:22 +0100, Giacomo Tesio wrote:
>
> Than probably its related with the InsertOnSubmit().
>
> Table<T> refer to the datacontext and surely register the entity.
> While registering it's probably deeply visited to locate any EntitySet and
> EntityRef filled.
> The entities filled are then registered (note that entity registration is
> idempotent: you should be able to register an entity many time without any
> problem)
>
> I try to take a look at it, now...
>
>
> Giacomo
>
> On Mon, May 11, 2009 at 6:29 PM, Jonathan Pryor <[email protected]> wrote:
>
> It's not a dumb question, and *yes* it passes on linq to sql.
>
> WriteTest.cs (which contains this test) is part of the
> DbLinq.SqlServer_test_strict project, which builds against SQL Server.
> These tests pass within that project.
>
> I'm not sure *how* Linq to SQL does it (is it EntitySet<T> that does it,
> or something else), but it is supported.  I doubt that EntitySet<T> is
> directly involved, though, since there isn't any connection between
> EntitySet<T> and DataContext (so there'd be no way afaik for
> EntitySet<T>.Add() to implicitly register values).
>
> - Jon
>
>
>
> On Mon, 2009-05-11 at 17:26 +0200, Giacomo Tesio wrote:
>
> I know it's a dumb question, but... do such a test pass on linq to sql?
>
> I would imagine that you should add the product to the product list too, to
> make it submitted.
> I mean you should
>
> db.Products.InsertOnSubmit(p);
>
>
>
> The alternative would be the EntitySet keeping track of entities added...
> (or asking to the datacontext to register each added entities...
>
>
> If it should work, it should not be too complex to do..
>
>
> Giacomo
>
>
> On Mon, May 11, 2009 at 4:55 PM, Jonathan Pryor <[email protected]> wrote:
>
> Actually, it's worse than I thought.  (Which is why I should add more
> assertions to my tests...)  The *real* problem is that inserting and
> updating only inserts/updates the immediate object, and not all referenced
> objects.  Thus, this (paraphrased from WriteTest.cs):
>
> Category c = new Category {...};
> Product  p = new Product {...};
> c.Products.Add(p);
> db.Categories.InsertOnSubmit(c);
> db.SubmitChanges();
>
> // This works: the Category IS inserted
> Assert.AreEqual(1, db.Categories.Where(c => c.CategoryName == ...).Count());
> // This fails: the referenced Product is NOT inserted
> Assert.AreEqual(1, db.Products.Where(p => p.ProductName == ...).Count());
>
>  Looks like QueryBuilder.GetInsertQuery() and
> QueryBuilder.GetUpdateQuery() are at fault, especially considering that
> they appear to assume that only one statement will be required (while more
> than one may be required when updating an entire object graph, as the above
> example requires).
>
> - Jon
>
>
>
> On Mon, 2009-05-11 at 01:10 -0400, Jonathan Pryor wrote:
>
> After more debugging, I'm heading to bed, but this is what I've found out:
> our change tracking isn't tracking changes. :-)
>
> Specifically, when you have code like this (using something NUnit-testable
> instead of from NerdDinner):
>
> Category c = GetExistingCategory();
> Product p = new Product {...};
> c.Products.Add(p);
> db.SubmitChanges();
>
>  the newly added product isn't actually added to the database.  The problem
> *appears* to be because of MemberModificationHandler: it only tracks
> INotifyPropertyChanged and not INotifyPropertyChanging (see
> MemberModificationHandler.RegisterNotification()).
>
> So, what happens is c is a tracked object (yay).  As such, it is
> registered with the EntityTracker (double yay).  However, for change
> tracking to work, MemberModificationHandler uses the
> INotifyPropertyChanged interface.  In this case, c.Products.Add(p) doesn't
> actually invoke MemberModificationHandler.OnPropertyChangedEvent(),
> because it isn't registered.
>
> Specifically, the registered Category fires the
> INotifyPropertyChanging.PropertyChanging event, because (as far as it
> knows) c.Products will be changing.  However, c doesn't know what, if
> anything, will change.  c.Products.Add(p) eventually calls into
> Category.attach_Products(), which then effectively does 'p.Category = c'.
> This last expression is what fires the
> INotifyPropertyChanged.PropertyChanged event, but only on p, which hasn't
> been registered with *anything*, and thus there are no handlers
> registered.
>
> Oops.
>
> The only solution I can think of is that MemberModificationHandler needs
> to listen to the INotifyPropertyChanging.PropertyChanging event (if
> available), and if it's fired it needs to check for changes on 
> *all*properties of the changing object.
>
> So I did this, and it still fails (see attached patch, which includes the
> unit test).  It properly detects that 'c' may have changed, but
> QueryRunner.Update() doesn't do a "deep" update; that is, it only updates
> the Category properties (CategoryName, Description, etc.) but not the
> values of anything attached to it (like the Category.Products collection).
>
> Any ideas on how to resolve this?
>
> Thanks,
> - Jon
>
> On Sun, 2009-05-10 at 22:02 -0400, Jonathan Pryor wrote:
>
> I already fixed this, and it has been committed to svn.
> DataContext.SetEntitySetQueries() was being called because of
> DataContext._GetOrRegisterEntity(), which in turn was called by
> DataContext.Register(), which was called by DataContext.SubmitChanges().
> (Just check the callstack in the original message...)  The problem was
> twofold:  (1) DbLinq's EntitySet<T> was screwy (though I blame a lot of
> that screwiness on .NET's EntitySet<T> -- see the new EntitySetTest.csfile, 
> and laugh hysterically when you see
> *when* the EntitySet<T>.ListChanged event is raised), and (2) calling
> dinner.RSVPs.Add(rsvp) caused the EntitySet<RSVP> source to be created,
> and EntitySet<T>.SetSource() cannot be called again once
> EntitySet<T>.HasLoadedOrAssignedValues is true.  Since
> DataContext.SetEntitySetsQueries() tried to do just that, it threw an
> exception.
>
> Now I'm working on a related bug: subsequent updates aren't tracked.  To
> wit:
>
> Dinner dinner = new Dinner {...};
> RSVP rsvp = new RSVP();
> rsvp.AttendeeName = User.Identity.Name;
> dinner.RSVPs.Add(rsvp);
> db.Dinners.InsertOnSubmit(dinner);
> db.SubmitChanges();
>
> // The above now works.  Now...
>
> RSVP rsvp2 = new RSVP();
> rsvp2.AttendeeName = "whatever";
> dinner.RSVPs.Add(rsvp2);
> db.SubmitChanges();
> // rsvp2 is NOT submitted to the database.
>
>  I'm still tracking down why this happens.  The attached patch file
> recreates this same scenario within the unit tests, and also (thankfully)
> fails.
>
> What I would appreciate is if you could look into the cache issues that I'm
> seeing. :-)
>
> Thanks,
> - Jon
>
> On Sun, 2009-05-10 at 23:41 +0100, Giacomo Tesio wrote:
>
> I think this is due to the "dinner.RSVPs.Add(rsvp);"  line where you
> actually fill the EntitySet.
>
> The DataContext.SetEntitySetQueries() should not run on just inserted
> entity, since they are yet filled.
>
>
> Tomorrow I'll try to fix this...
>
>
> Giacomo
>
>
> On Fri, May 8, 2009 at 4:59 AM, Jonathan Pryor <[email protected]> wrote:
>
> Still continuing with my "NerdDinner on Mono" effort, and hitting the
> following issue:
>
> When I attempt to add a new Dinner, NerdDinner effectively does:
>
> Dinner dinner = new Dinner {...};
> RSVP rsvp = new RSVP();
> rsvp.AttendeeName = User.Identity.Name;
> dinner.RSVPs.Add(rsvp);
> db.Dinners.InsertOnSubmit(dinner);
> db.SubmitChanges();
>
>  This fails, with:
>
> System.Reflection.TargetInvocationException: Exception has been thrown by the 
> target of an invocation. ---> System.InvalidOperationException: The EntitySet 
> is already loaded and the source cannot be changed.
>   at System.Data.Linq.EntitySet`1[NerdDinner.Models.RSVP].SetSource 
> (IEnumerable`1 entitySource) [0x00000]
>   at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke 
> (object,object[],System.Exception&)
>   at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags 
> invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, 
> System.Globalization.CultureInfo culture) [0x000ca] in 
> /home/jon/Development/mono-HEAD/mcs/class/corlib/System.Reflection/MonoMethod.cs:169
>   --- End of inner exception stack trace ---
>   at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags 
> invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, 
> System.Globalization.CultureInfo culture) [0x000e5] in 
> /home/jon/Development/mono-HEAD/mcs/class/corlib/System.Reflection/MonoMethod.cs:179
>   at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] 
> parameters) [0x00000] in 
> /home/jon/Development/mono-HEAD/mcs/class/corlib/System.Reflection/MethodBase.cs:111
>   at System.Data.Linq.DataContext.SetEntitySetsQueries (System.Object entity) 
> [0x00173] in 
> /home/jon/Development/mono-HEAD/mcs/class/System.Data.Linq/src/DbLinq/Data/Linq/DataContext.cs:608
>   at System.Data.Linq.DataContext._GetOrRegisterEntity (System.Object entity) 
> [0x00015] in 
> /home/jon/Development/mono-HEAD/mcs/class/System.Data.Linq/src/DbLinq/Data/Linq/DataContext.cs:468
>   at System.Data.Linq.DataContext.Register (System.Object entity) [0x0000d] 
> in 
> /home/jon/Development/mono-HEAD/mcs/class/System.Data.Linq/src/DbLinq/Data/Linq/DataContext.cs:675
>   at System.Data.Linq.DataContext.SubmitChanges (ConflictMode failureMode) 
> [0x000a6] in 
> /home/jon/Development/mono-HEAD/mcs/class/System.Data.Linq/src/DbLinq/Data/Linq/DataContext.cs:378
>   at System.Data.Linq.DataContext.SubmitChanges () [0x00000] in 
> /home/jon/Development/mono-HEAD/mcs/class/System.Data.Linq/src/DbLinq/Data/Linq/DataContext.cs:339
>   at NerdDinner.Models.DinnerRepository.Save () [0x00000]
>   at NerdDinner.Controllers.DinnersController.Create 
> (NerdDinner.Models.Dinner dinner) [0x00000]
>
>  Suffice it to say, this doesn't happen under .NET's System.Data.Linq.  I'm
> wondering if anyone has seen a similar error to this before, and/or knows
> what an appropriate fix would be.
>
> Thanks,
> - Jon
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> >
>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"DbLinq" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/dblinq?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to