PlaylistCollection クラスと 1 対多の関係を持つ User クラスがあります。同様に、PlaylistCollection は Playlist クラスと 1 対多の関係にあります。
新しい User オブジェクトを作成してデータベースに保存したいと考えています。副作用として、新しい 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 を持つユーザーをデータベースに書き込むことはできますが、User -> PlaylistCollection -> Playlist ではできません。
私のマッピング:
<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 オブジェクトが CollectionId の Guid.Empty を使用して自身を保存しようとしていることです。PlaylistCollection の保存時に生成されたものの CollectionId を使用して、それ自体を保存しようとする必要があります。
更新:これは機能しますが、明らかに強制されています。どうすれば改善できますか?
// Playlist クラスの内部:
[DataMember(Name = "collectionId")]
public Guid CollectionId
{
get { return Collection.Id; }
set { Collection.Id = value; }
}
public PlaylistCollection Collection { get; set; }
これを行うと、自分の collectionId を返すことができ、NHibernate は現在、適切にマッピングを把握しています... しかし、それでも私には少し無理があるように思えます。