It looks like you're using Guid.Comb from the mapping you provided. This is good, as it should help prevent these sorts of problems. What flush mode are you using?
On Wed, Nov 26, 2008 at 4:52 AM, Graham Bunce <[EMAIL PROTECTED]> wrote: > > This problem is driving me up the wall and I can't see any reason for > it. So help (or an admission that its a bug) would be helpful. > > HNibernate 2.0.1GA with SQL Server 2005 > > I'm implementing what has become the defacto repository pattern in > that my domain layer has an interface that the repository (based on > NHibernate) implements. I'm using Microsoft Unity as my Service > Locator to load up the NHibernate enabled repository. > > I have code such as this (which is a perfectly valid scenario in any > business I would think) > > ===> > IAsset newAsset = Factory.Create<IAsset>(); > newAsset.Name = "New name"; > > IContent newContent = Factory.Create<IContent>(); > newContent.Name = "New content"; > > IAssetContent newAssetContent = newAsset.AddContent(newContent); > newAssetContent.Quantity = 100; > > repository.Add(newAsset); > repository.Add(newContent); > repository.Add(newAssetContent); > > repository.Persist(); // All this does is a Session.Flush() wrapped > in a NHibernate transaction. > > <== > > This line: "repository.Add(newAsset);" fails with a "not-null > property references a null or transient value" on Content. I have > tried the following: > > 1) Move line to after the factory create of an asset. Result = Success > BUT NHibernate issues an INSERT for the Asset followed by an UPDATE > for the change of name. It works, but it's inefficent > > 2) Move "repository.Add(newContent);" to after IContent newContent = > Factory.Create<IContent>();. Result = Success, same SQL generated as > (1) though. > > 3) Move "repository.Add(newContent);" or "repository.Add > (newAssetContent);" to before the add of an Asset. Result = Fail, same > reason as described but missing value is Asset, not Content. > > > It appears that there are two (three?) problems here > > 1) The order objects are added to the repository actually makes a big > difference (I can't add a child before its parent) but assuming they > are all unsaved then this doesn't make sense - my "Persistent > Ignorant" domain later doesn't care how or when objects get created. > It just adds them to the repository (which is acting as my Unit of > Work) when it's done with them. When the persist takes place, that's > when all the magic happens and they get saved in order. > > (see this post "Beginner: First insert of persistent entity Options" > and Thomas Krause comment that has not been answered as far as I can > tell: "NHibernate doesn't seem to reorder the inserts automatically. > Looking at the code it seems that there is some code in ActionQueue to > do this ordering, but it is commented out and I assume not finished in > the current version") > > 2) For some reason, I cannot just add them to the repository when I'm > done... I have to add them, then work on them (but only cases I cannot > fathom) though this creates SQL that is pointless. My domain layer > needs to be careful what gets added when - this seems to be such a > flakey situation that adding something new to the object model could > cause a break that won't be easy to track down. > > 3) INSERTS and UPDATES are issued when not neccessary > > I've read the argument is that you have saved an object to NHibernate, > it creates the need for an Insert..... then the update comes along and > NHibernate is being fantastic by working out a change has occured. Ok, > fair enough - but I haven't actually Persisted them yet. I've only > added them to my Unit Of Work (i.e. the Session). NHibernate should be > smart enough to know that it has never saved this to the DB, been > subsequently changed, but it isn't actually saved to the DB so it can > combine the Insert and Update together. > > I know that's what the empty ID option is for and by doing the > Session.Save() it overwrites this so that is why I tried to stack my > add's up until I was ready...but the crash mentioned above prevents me > doing that. > > So I'm basically stuck. > > > Mapping files for interest: > > <?xml version="1.0" encoding="utf-8" ?> > <hibernate-mapping > xmlns="urn:nhibernate-mapping-2.2" > namespace="Domain.SupplyChain" > assembly="Domain.SupplyChain" > default-access="field.camelcase-underscore" > default-lazy="true"> > <class name="Asset" > proxy="Domain.SupplyChain.Interfaces.IAsset, > Domain.SupplyChain.Interfaces" > table="Asset"> > <id name="Id" column="Id" unsaved- > value="00000000-0000-0000-0000-000000000000" access="property"> > <generator class="guid.comb" /> > </id> > <property name="Name" type="string" length="255" not-null="true" / >> > <bag name="AssetContents" table="AssetContents" inverse="true" > cascade="all" > > <key column="AssetId" /> > <one-to-many class="AssetContent" /> > </bag> > </class> > </hibernate-mapping> > > <?xml version="1.0" encoding="utf-8" ?> > <hibernate-mapping > xmlns="urn:nhibernate-mapping-2.2" > namespace="Domain.SupplyChain" > assembly="Domain.SupplyChain" > default-access="field.camelcase-underscore" > default-lazy="true"> > <class name="Content" > proxy="Domain.SupplyChain.Interfaces.IContent, > Domain.SupplyChain.Interfaces" > table="Content"> > <id name="Id" column="Id" unsaved- > value="00000000-0000-0000-0000-000000000000" access="property"> > <generator class="guid.comb" /> > </id> > <property name="Name" type="string" length="255" not-null="true" / >> > <bag name="AssetContents" table="AssetContents" inverse="true" > cascade="all" > > <key column="ContentId" /> > <one-to-many class="AssetContent" /> > </bag> > </class> > </hibernate-mapping> > > <?xml version="1.0" encoding="utf-8" ?> > <hibernate-mapping > xmlns="urn:nhibernate-mapping-2.2" > namespace="Domain.SupplyChain" > assembly="Domain.SupplyChain" > default-access="field.camelcase-underscore" > default-lazy="true"> > <class name="AssetContent" > proxy="Domain.SupplyChain.Interfaces.IAssetContent, > Domain.SupplyChain.Interfaces" > table="AssetContent"> > <id name="Id" column="Id" unsaved- > value="00000000-0000-0000-0000-000000000000" access="property"> > <generator class="guid.comb" /> > </id> > <many-to-one name="Asset" column="AssetId" class="Asset" not- > null="true" /> > <many-to-one name="Content" column="ContentId" class="Content" not- > null="true" /> > <property name="Quantity" type="int" not-null="true" /> > </class> > </hibernate-mapping> > > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "nhusers" 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/nhusers?hl=en -~----------~----~----~----~------~----~------~--~---
