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