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]<mailto:[email protected]>.
To post to this group, send email to 
[email protected]<mailto:[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.


Reply via email to