Why not use the many-to-one as part of your composite (using key-many-to-one)? it can still be an entity just like it is now and you'll eliminate the duplication and the smells.
If you want to keep the many-to-one out of the id itself ( for instance you many want to use the ID object pattern, which allows your object to be cached) then make your id object (or identifier if you're not doing the id object thing) protected - NHibernate can still update it, and then whenever you assign a playlist with your (public) many-to-one OBJECT reference, also set the value of your identifier/id object. Then, set your playlistid to be readonly(insert=false and update=false) in your nhibernate mapping-so you won't have those duplicate-use issues, but it will still hydrate for you. eh, just read the post I wrote on composite keys a few years ago, composite keys are wonky but it covers pretty much everything: http://devlicio.us/blogs/anne_epstein/archive/2009/11/20/nhibernate-and-composite-keys.aspx On Tue, Apr 2, 2013 at 4:47 PM, Sean Anderson <[email protected]> wrote: > I'm hoping not to argue semantics and "you should not use a composite key" > with this post. I understand the implications of composite key use, but > believe it to be best suited for my task at hand. > > I have the following in "PlaylistItem.hbm.xml:" > > <?xml version="1.0" encoding="utf-8" ?><hibernate-mapping > xmlns="urn:nhibernate-mapping-2.2" assembly="Streamus" > namespace="Streamus.Backend.Domain"> > > <class name="PlaylistItem" table="[PlaylistItems]" lazy="false" > > <composite-id> > <key-property name="Id" /> > <key-property name="PlaylistId"/> > </composite-id> > > <property name="Title" not-null="true" /> > > <many-to-one name="Playlist" column="PlaylistId"/> > </class> > </hibernate-mapping> > > which corresponds with the following class: > > [DataContract]public class PlaylistItem{ > [DataMember(Name = "playlistId")] > public Guid PlaylistId > { > get { return Playlist.Id; } > set { Playlist.Id = value; } > } > > public Playlist Playlist { get; set; } > > [DataMember(Name = "id")] > public Guid Id { get; set; } > > // Store Title on PlaylistItem as well as on Video because user might > want to rename PlaylistItem. > [DataMember(Name = "title")] > public string Title { get; set; } > > public PlaylistItem() > { > // Id shall be generated by the client. This is OK because it is > composite key with > // PlaylistId which is generated by the server. > Id = Guid.Empty; > Title = string.Empty; > } > > private int? _oldHashCode; > public override int GetHashCode() > { > // Once we have a hash code we'll never change it > if (_oldHashCode.HasValue) > return _oldHashCode.Value; > > bool thisIsTransient = Equals(Id, Guid.Empty); > > // When this instance is transient, we use the base GetHashCode() > // and remember it, so an instance can NEVER change its hash code. > if (thisIsTransient) > { > _oldHashCode = base.GetHashCode(); > return _oldHashCode.Value; > } > return Id.GetHashCode(); > } > > public override bool Equals(object obj) > { > PlaylistItem other = obj as PlaylistItem; > if (other == null) > return false; > > // handle the case of comparing two NEW objects > bool otherIsTransient = Equals(other.Id, Guid.Empty); > bool thisIsTransient = Equals(Id, Guid.Empty); > if (otherIsTransient && thisIsTransient) > return ReferenceEquals(other, this); > > return other.Id.Equals(Id); > }} > > > This clearly generates an exception with NHibernate because the property > "PlaylistId" is referenced through the composite key definition as well as > in the many-to-one definition. I am obstinate about using PlaylistId as > part of the composite key. I would also like to leverage as much of > NHibernate's built-in capabilities in order to preserve data integrity. > > I've implemented the following as a work-around, but I am not happy with > my change. I am not using NHibernate's ability to automatically dehydrate > Playlist when loading a PlaylistItem: > > public Guid PlaylistId{ > get > { > return Playlist == null ? Guid.Empty : Playlist.Id; > } > set > { > if (Playlist == null || Playlist.Id != value) > { > Playlist = new PlaylistDao().Get(value); > } > }} > > in addition to this change, I remove <many-to-one name="Playlist" column= > "PlaylistId"/> > > This works as expected. Whenever NHibernate dehydrates the PlaylistId via > the composite key, PlaylistItem's Playlist property is set. However, the > code obviously smells. I am wondering -- do I have any options here? Or, is > this an unsupported scenario in NHibernate? > > Thanks > > -- > 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?hl=en. > 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?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
