1

子テーブルとのオプションの1:1 関係を持つ親テーブルがあります (親は子なしで存在できますが、その逆はできません)。親テーブルの自動生成された主キーは、子の主/外部キーとして使用されます。

いくつかの良い参考文献 (この質問このサイト)のおかげで、1 対 1 の関係を計画することができました。予想どおり、子の有無にかかわらず親を作成し、一方または両方を更新し、親カスケードを削除して子を削除できます。

ただし、マッピング構造内のマッピングのCascade.AllDeleteOrphan()オプションを何とか「シミュレート」したいので、関係の子側が削除されると、親オブジェクトが保存されるときに子テーブルの対応する行が削除されます。そのまま、子を手動で削除しようとすると、当然のことながらエラー メッセージが表示されます。HasManyHasOne'deleted object would be re-saved by cascade'

HasOneまだマッピングのみを使用しているときに、これを行う良い方法を見つけた人はいますか? 私がやろうとしていることは、まだ 1 対 1 の関係でしょうか? それとも、1 対多を使用して、データベースの制約とビジネス ロジックに依存して、複数の子を防止する必要がありますか?

簡略化されたコード:

// Parent class
public partial class Parent
{
    public int pkParentID { get; set; }
    public Child child { get; set; }
    public Parent() { }
}

// Child class
public partial class Child
{
    public int pkParentID {get; set; }
    public Parent parent { get; set; }
    public Child() { }
    public Child(Parent parent) { this.parent = parent; }
}

// Parent mapping
public class ParentMap : ClassMap<Parent>
{
    public ParentMap()
    {
        Table(@"Parent");
        LazyLoad();
        Id(x => x.pkParentID)
          .Column("pkProjectID")
          .Not.Nullable()
          .GeneratedBy.Identity();
        HasOne<Child>(x => x.Child)
          .PropertyRef(r => r.Parent)
          .Cascade.All();
    }
}

// Child map
public class ChildMap :ClassMap<Child>
{
    public ChildMap()
    {
          Table(@"Child");
          LazyLoad();
          Id(x => x.pkParentID, "pkParentID") 
            .GeneratedBy.Foreign("Parent");
          HasOne<Parent>(x => x.Parent)
            .Constrained()
            .ForeignKey()
            .Cascade.None();
    }
}


// Ideally, the code snippet below would remove the row from the Child table
Parent parent = service.GetById(uniqueID);
if (parent.Child != null)
    parent.Child = null;
service.SaveOrUpdate(parent);


// Just in case, here's my repository code
public virtual void SaveOrUpdate(T entity)
{
    ISession _session = NHibernateSessionProvider.GetSession();
    if (!_session.Transaction.IsActive)
    {
        using (ITransaction transaction = _session.BeginTransaction())
        {
            try
            {
                _session.SaveOrUpdate(entity);
                transaction.Commit();
            }
            catch
            {
                transaction.Rollback();
            }
        }
    }
}

編集::次のコードスニペットも試しました。これにより、「削除されたオブジェクトはカスケードによって再保存されます」というエラーメッセージが表示されます。

...
Parent parent = parentService.GetById(uniqueID);
if (parent.Child != null)
{
    childService.Remove(parent.Child);  // this gives the above error
    parent.Child = null;
}
4

1 に答える 1

0

カスケード設定all-delete-orphanは、NHibernateには実装されていません。NH -1262を参照してください。この問題に関するコメントにプルリクエストがあるため、将来のバージョンで提供される可能性があります。

今のところ、次のことができます。

Parent parent = service.GetById(uniqueID);
parent.Child = null;
service.Delete(parent.Child); // probably needs to occur in a different repository
// commit transaction or flush session, there's no need to call SaveOrUpdate
于 2013-02-06T16:00:08.677 に答える