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.cs file, 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