2

我有一个对象 PlaylistItem,它在通过 ID 引用其下一个 PlaylistItem 时保存得很好。尝试修改此代码以引用实际的 PlaylistItem 对象本身时遇到异常。我了解该问题是由我的 hbm.xml 文件中的重复映射引起的。但是,我无法为我的场景找到解决方案。

这是目前的 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-many-to-one name="Playlist" column="PlaylistId"/>
    </composite-id>

    <property name="Title" not-null="true" />

    <many-to-one name="Video" column="VideoId" not-null="true" />

    <many-to-one name="NextItem" not-null="true">
      <column name="NextItemId" />
      <column name="PlaylistId" />
    </many-to-one>
  </class>

</hibernate-mapping> 

我可以通过修改 NextItem 多对一关系使其具有属性“insert="false" update="false" 来避免此异常。但是,这样做会导致 NextItem 在数据库中始终为 NULL。

这是相关的类:

public class PlaylistItem
{
    public Guid Id { get; set; }
    public Playlist Playlist { get; set; }
    public PlaylistItem NextItem { get; set; }
    public string Title { get; set; }
    public Video Video { 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);
    }
}

无论 NextItem 是否已定义或为 null,都会引发异常。我坚信我需要使用复合键来唯一地表示 PlaylistItem。

我有哪些选择?我不确定如何进一步解决这个问题。

这是保存前我的对象手表的屏幕截图:

在此处输入图像描述

如前所述,我还尝试在 NextItem 为空的情况下进行保存。此外,我尝试让 Ne​​xtItem 完全成为另一个 PlaylistItem(这样 PlaylistItem 就不是自引用的。)这些更改都没有任何效果。

这是异常的屏幕截图:

在此处输入图像描述

异常显示为“Count=5 的此 SqlParamaterCollection 的索引 5 无效。” 没有定义内部异常。

以下是屏幕截图中引用的 PlaylistItem 的构造函数:

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;
}

public PlaylistItem(Guid id, string title, Video video)
    : this()
{
    Id = id;
    Title = title;
    Video = video;
}

这是 Playlist 的构造函数及其 AddItem 方法:

public Playlist()
{
    Id = Guid.Empty;
    Title = string.Empty;
    Items = new List<PlaylistItem>();
}

public Playlist(string title)
    : this()
{
    Title = title;
}

/// <summary>
///     Add a PlaylistItem to the Playlist's PlaylistItem collection by inserting
///     the PlaylistItem at the end of the linked list. Adjust the links
///     to accomodate the PlaylistItem and set the Playlist's FirstItem
///     if necessary.
/// </summary>
public void AddItem(PlaylistItem playlistItem)
{
    if (Items.Count == 0)
    {
        playlistItem.NextItem = playlistItem;
        playlistItem.PreviousItem = playlistItem;
        FirstItem = playlistItem;
    }
    else
    {
        //  Adjust our linked list and add the item.
        FirstItem.PreviousItem.NextItem = playlistItem;
        playlistItem.PreviousItem = FirstItem.PreviousItem;

        FirstItem.PreviousItem = playlistItem;
        playlistItem.NextItem = FirstItem;
    }

    Items.Add(playlistItem);
    playlistItem.Playlist = this;
}

这是 PlaylistManager 的构造函数及其 Save 方法:

public PlaylistManager(IPlaylistDao playlistDao, IPlaylistItemDao playlistItemDao, IVideoDao videoDao)
{
    PlaylistDao = playlistDao;
    PlaylistItemDao = playlistItemDao;
    VideoDao = videoDao;
}

public void Save(Playlist playlist)
{
    try
    {
        NHibernateSessionManager.Instance.BeginTransaction();

        playlist.ValidateAndThrow();
        PlaylistDao.Save(playlist);

        NHibernateSessionManager.Instance.CommitTransaction();
    }
    catch (Exception exception)
    {
        Logger.Error(exception);
        NHibernateSessionManager.Instance.RollbackTransaction();
        throw;
    }
}

PlaylistDao 的 Save 方法只是 NH​​ibernateSession.Save(entity); 的一个包装器。

4

0 回答 0