我有一个 User 类,它与 PlaylistCollection 类具有一对多的关系。同样,PlaylistCollection 与 Playlist 类具有一对多的关系。
我想创建一个新的用户对象并将其保存到数据库中。作为副作用,我希望一个新的 PlaylistCollection 和一个新的 Playlist 也被写入数据库。当我调用 commit -- NHibernate 抛出异常:
exec sp_executesql N'INSERT INTO [Playlists] (CollectionId, Title, Position, Id) VALUES (@p0, @p1, @p2, @p3)',N'@p0 uniqueidentifier,@p1 nvarchar(4000),@p2 int,@p3 uniqueidentifier',@p0='00000000-0000-0000-0000-000000000000',@p1=N'New Playlist',@p2=0,@p3='CD593D78-5300-434E-B256-6271D4A60915'
The INSERT statement conflicted with the FOREIGN KEY constraint "FK66D0C3A319AEA85C". The conflict occurred in database "StreamusTest", table "dbo.PlaylistCollections", column 'Id'.
如果我省略给我的 PlaylistCollection 一个初始的 Playlist 对象,则不会发生此错误。我可以将具有 PlaylistCollection 的用户写入数据库,但不是用户 - > PlaylistCollection - > 播放列表。
我的映射:
<class name="User" table="[Users]" lazy="false">
<id name="Id" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid" />
</id>
<property name="Name" />
<bag name="PlaylistCollections" cascade="all-delete-orphan" >
<key column="UserId" />
<one-to-many class="PlaylistCollection" />
</bag>
</class>
<class name="PlaylistCollection" table="[PlaylistCollections]" lazy="false" >
<id name="Id" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid" />
</id>
<property name="Title" not-null="true" />
<bag name="Playlists" cascade="all-delete-orphan" >
<key column="CollectionId" />
<one-to-many class="Playlist" />
</bag>
</class>
<class name="Playlist" table="[Playlists]" lazy="false" >
<id name="Id" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid" />
</id>
<property name="CollectionId" not-null="true" />
<property name="Title" not-null="true" />
<property name="Position" not-null="true" />
<bag name="Items" cascade="all-delete-orphan" >
<key column="PlaylistId" />
<one-to-many class="PlaylistItem" />
</bag>
</class>
和实体构造函数/辅助方法:
public User()
{
Name = string.Empty;
PlaylistCollections = new List<PlaylistCollection>
{
new PlaylistCollection("New Playlist Collection")
};
}
public PlaylistCollection()
{
Id = Guid.Empty;
UserId = Guid.Empty;
Title = string.Empty;
Playlists = new List<Playlist>();
// A collection should always have at least one Playlist.
CreatePlaylist();
}
public PlaylistCollection(string title)
: this()
{
Title = title;
}
public Playlist()
{
Id = Guid.Empty;
CollectionId = Guid.Empty;
Title = string.Empty;
Position = -1;
Items = new List<PlaylistItem>();
}
public Playlist CreatePlaylist()
{
string playlistTitle = string.Format("New Playlist {0:D4}", Playlists.Count);
var playlist = new Playlist(playlistTitle);
return AddPlaylist(playlist);
}
public Playlist AddPlaylist(Playlist playlist)
{
if (Id != Guid.Empty)
{
playlist.CollectionId = Id;
}
playlist.Position = Playlists.Count;
Playlists.Add(playlist);
return playlist;
}
最后,这是失败的方法:
/// <summary>
/// Creates a new User and saves it to the DB. As a side effect, also creates a new, empty
/// PlaylistCollection (which has a new, empty Playlist) for the created User and saves it to the DB.
/// </summary>
/// <returns>The created user with a generated GUID</returns>
public User CreateUser()
{
User user;
try
{
NHibernateSessionManager.Instance.BeginTransaction();
user = new User();
user.ValidateAndThrow();
UserDao.Save(user);
NHibernateSessionManager.Instance.CommitTransaction();
}
catch (Exception exception)
{
Logger.Error(exception);
NHibernateSessionManager.Instance.RollbackTransaction();
throw;
}
return user;
}
显然,问题在于 Playlist 对象正在尝试使用 Guid.Empty 的 CollectionId 来保存自己。它应该尝试使用在保存 PlaylistCollection 时生成的任何内容的 CollectionId 来保存自己。
更新:这可行,但显然是被迫的。我该如何改进它?
// 播放列表类内部:
[DataMember(Name = "collectionId")]
public Guid CollectionId
{
get { return Collection.Id; }
set { Collection.Id = value; }
}
public PlaylistCollection Collection { get; set; }
这样做可以让我返回我的 collectionId 并且 NHibernate 现在已经正确地找出了映射......但对我来说似乎仍然有点强迫。