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.