The architectural flaw would be this: var videoInDatabase = new Video(randomVideoId, videoTitle, 999, "Author");
Newing up something that you know is in the database. var videoInDatabase = VideoDao.Get(randomVideoId); or (given a modification to the Dao, which uses Load instead of Get) var videoInDatabase = VideoDao.GetReference(randomVideoId); if you want to avoid the database roundtrip. /G 2013/7/1 Tyler Burd <[email protected]> > If you map the Video class as “lazy”, and simply do a > Session.Load(yourVideoId), NH will not actually fetch the video from the > database; it will fetch it from the session cache (if the entity has > already been loaded), or just give you a simple proxy. Even with > immutables, NHibernate does not like it when multiple instances have the > same id.**** > > ** ** > > *From:* [email protected] [mailto:[email protected]] *On > Behalf Of *Sean Anderson > *Sent:* Monday, July 01, 2013 11:16 AM > *To:* [email protected] > *Subject:* [nhusers] NonUniqueObjectException when working with an > immutable entity. Possible to suppress?**** > > ** ** > > Hey guys,**** > > ** ** > > I've hit a snag while working with NHibernate and I'm not sure if the > problem is incredibly trivial or incredibly complex. Naturally, I'm hoping > for the former. Here's an explanation of my scenario:**** > > ** ** > > I have an immutable entity, Video, which has an assigned ID:**** > > ** ** > > <class name="Video" table="[Videos]" lazy="false" mutable="false">**** > > <id name="Id" length="11" type="String">**** > > <generator class="assigned"></generator>**** > > </id>**** > > ** ** > > <property name="Title" not-null="true" />**** > > <property name="Duration" not-null="true" />**** > > <property name="Author" not-null="true" />**** > > </class>**** > > I then create and save two detached Video entities which have the same ID. > NHibernate throws a NonUniqueObjectException when I attempt to save the > second Video. Here's a failing test case:**** > > public void CreateItem_VideoAlreadyExists_ItemCreatedVideoNotUpdated()**** > > {**** > > // Save this Video before continuining so that it exists before adding > the PlaylistItem.**** > > string randomVideoId = Guid.NewGuid().ToString().Substring(0, 11);**** > > var videoNotInDatabase = new Video(randomVideoId, "Video", 999, > "Author");**** > > VideoManager.Save(videoNotInDatabase);**** > > ** ** > > // Change the title for videoInDatabase to check that cascade-update > does not affect title. Videos are immutable.**** > > const string videoTitle = "A video title";**** > > var videoInDatabase = new Video(randomVideoId, videoTitle, 999, > "Author");**** > > ** ** > > // Create a new PlaylistItem and write it to the database.**** > > string title = videoInDatabase.Title;**** > > var playlistItem = new PlaylistItem(title, videoInDatabase);**** > > ** ** > > Playlist.AddItem(playlistItem);**** > > PlaylistManager.SavePlaylistItem(playlistItem);**** > > ** ** > > // Remove entity from NHibernate cache to force DB query to ensure > actually created.**** > > NHibernateSessionManager.Instance.Clear();**** > > ** ** > > // Ensure that the Video was NOT updated by comparing the new title to > the old one.**** > > Video videoFromDatabase = VideoDao.Get(randomVideoId);**** > > Assert.AreNotEqual(videoFromDatabase.Title, videoTitle);**** > > ** ** > > // Ensure that the PlaylistItem was created.**** > > PlaylistItem itemFromDatabase = PlaylistItemDao.Get(playlistItem.Id);**** > > Assert.NotNull(itemFromDatabase);**** > > ** ** > > // Pointers should be self-referential with only one item in the > Playlist.**** > > Assert.AreEqual(itemFromDatabase.NextItem, itemFromDatabase);**** > > Assert.AreEqual(itemFromDatabase.PreviousItem, itemFromDatabase);**** > > }**** > > This test case fails on "PlaylistManager.SavePlaylistItem" which is just a > transaction wrapper for calling NHibernate's ISession.Save.**** > > I understand why (and my options, such as Merge, Evict, or Refresh) but I > feel like an option is missing. My Video entity is immutable, so it cannot > be updated. NHibernate already knows about the Video because it is in its > cache, so it cannot be inserted. As such, even though NHibernate throws a > NonUniqueObjectException… in reality, no operation can occur on the entity. > I have been unable to find a way to express this to NHibernate.**** > > I am opposed to having to refresh the Video entity because it is the child > of a large hierarchy of parent entities. Iterating to the bottom of the > hierarchy for each entity in the collection, just to call Refresh on a > Video, seems like an extremely bad design decision.**** > > I understand that if I used a Versioning system that NHibernate would be > able to determine that the two entities are unique. However, I do not wish > for them to be treated as such. I only want one Video with a given ID to be > written to my table.**** > > Full details can be found here: > http://stackoverflow.com/questions/17396362/nonuniqueobjectexception-thrown-after-client-attempts-to-save-the-same-item-twic > **** > > Do I have an architectural flaw? Am I missing a simple keyword? Or is this > 'hard' for other reasons?**** > > Thanks for taking the time to read. Cheers,**** > > Sean Anderson**** > > -- > You received this message because you are subscribed to the Google Groups > "nhusers" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To post to this group, send email to [email protected]. > Visit this group at http://groups.google.com/group/nhusers. > For more options, visit https://groups.google.com/groups/opt_out. > > **** > > -- > You received this message because you are subscribed to the Google Groups > "nhusers" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To post to this group, send email to [email protected]. > Visit this group at http://groups.google.com/group/nhusers. > For more options, visit https://groups.google.com/groups/opt_out. > > > -- You received this message because you are subscribed to the Google Groups "nhusers" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/nhusers. For more options, visit https://groups.google.com/groups/opt_out.
