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 -~----------~----~----~----~------~----~------~--~---
