4

以下に定義する1対多の関係として相互に参照する2つの単純なクラスがあります。

public class Project
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<Document> Documents { get; set; }
}

public class Document
{
    public virtual int Id { get; set; }
    public string FileName { get; set; }
}

そして私のマッピングは次のように定義されています:

public class ProjectMapping : ClassMap<Project>
{
    public ProjectMapping()
    {
        Table("Projects");
        Id(x => x.Id).Column("Project_Id").GeneratedBy.TriggerIdentity();
        HasMany(x => x.Documents)
            .Table("Documents")
            .KeyColumn("Document_Project_Id")
            .Cascade.AllDeleteOrphan()
            .Not.KeyNullable();
        Map(x => x.Name).Column("Project_Name");
    }
}

public class DocumentMapping : ClassMap<Document>
{
    public DocumentMapping()
    {
        Table("Documents");
        Id(x => x.Id).Column("Document_Id").GeneratedBy.TriggerIdentity();
        Map(x => x.FileName).Column("Document_File_Name");
    }
}

ドキュメントの追加/更新とsession.Save(project)の呼び出しはすべて正常に機能しているようですが、プロジェクトに関連付けられたドキュメントのリストからドキュメントを削除してsession.Save(プロジェクト)削除されたドキュメントがデータベースから削除されることはありません。

削除以外のすべてが機能する理由はありますか?

編集: 私のMVC 4プロジェクトは、FluentNHibernateで次のように設定されています。

public class SessionFactoryHelper
{
    public static ISessionFactory CreateSessionFactory()
    {
        var c = Fluently.Configure();
        try
        {
            //Replace connectionstring and default schema
            c.Database(OdbcConfiguration.MyDialect.
                ConnectionString(x =>
                x.FromConnectionStringWithKey("DBConnect"))
                .Driver<NHibernate.Driver.OdbcDriver>()
                .Dialect<NHibernate.Dialect.Oracle10gDialect>())
                .ExposeConfiguration(cfg => cfg.SetProperty("current_session_context_class", "web"));
            c.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Project>());
            c.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Document>());
        }
        catch (Exception ex)
        {
            Log.WriteLine(ex.ToString());
        }
        return c.BuildSessionFactory();
    }
}

public class MvcApplication : System.Web.HttpApplication
{
    public static ISessionFactory SessionFactory { get; private set; }

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();

        SessionFactory = SessionFactoryHelper.CreateSessionFactory();
    }

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        var session = SessionFactory.OpenSession();
        CurrentSessionContext.Bind(session);
    }

    protected void Application_EndRequest(object sender, EventArgs e)
    {
        var session = CurrentSessionContext.Unbind(SessionFactory);
        session.Dispose();
    }
}

私のリポジトリは次のように定義されています。

public class Repository<T> : IRepository<T>
{
    public virtual ISession Session
    {
        get { return MvcApplication.SessionFactory.GetCurrentSession(); }
    }

    public T FindById(int iId)
    {
        return Session.Get<T>(iId);
    }

    public void Save(T obj)
    {
        using (var transaction = Session.BeginTransaction())
        {
            try
            {
                Session.Save(obj);
                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();

                Log.WriteLine(ex.ToString());
            }
        }
    }

    public T SaveOrUpdate(T obj)
    {
        using (var transaction = Session.BeginTransaction())
        {
            try
            {
                Session.SaveOrUpdate(obj);
                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();

                Log.WriteLine(ex.ToString());
            }
        }

        return obj;
    }

    public T Update(T obj)
    {
        using (var transaction = Session.BeginTransaction())
        {
            try
            {
                Session.Update(obj);
                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();

                Log.WriteLine(ex.ToString());
            }
        }

        return obj;
    }
}

ProjectsControllerで次のように2つのアクションを定義しています。

private IRepository<Project> repository;

public ProjectsController()
{
    repository = new Repository<Project>();
}

public ActionResult Edit(int iId)
{
    Project project = repository.FindById(iId);

    if (project == null)
        return HttpNotFound();

    return View(project);
}

[HttpPost]
public ActionResult Edit(Project project)
{
    project = repository.Update(project);

    return View(project);
}

最初のアクション(HttpPostなし)でドキュメントを削除する場合:

project.Documents.RemoveAt(0);
repository.Update(project);

正しい行がデータベースから削除されます。ただし、HttpPost属性を使用したアクションでまったく同じことを行う場合、行が削除されることはありません。

また、HttpPost属性を持つアクションのproject.Documentsにドキュメントを追加すると、repository.Update(project)は、プロジェクトへの正しい外部キー参照を持つ行を正常に追加することに注意する必要があります。これは、ドキュメントを削除したときにのみ失敗します。

4

2 に答える 2

3

マッピングに追加しようとし.Inverseましたか?HasMany

また、私はに慣れていませんNot.KeyNullable。ここでは必要ないと思います。

于 2012-11-26T22:32:02.573 に答える
2

カスケード設定は正しいようです。言及された問題は別の場所にある可能性があります。

ただし、プロジェクトに関連付けられたドキュメントのリストからドキュメントを削除する場合

私には、セッションフラッシュモード、またはProject以前に切り離された親エンティティを更新するための明示的な呼び出しがないことが疑われます。保証:

まず、Flush()が呼び出されたこと。そのprojectインスタンスがまだセッションに保持されている場合は、フラッシュのデフォルトの動作を変更できます。(例:session.FlushMode = FlushMode.Never;またはCommit取引なしで...)

// 1) checking the explicit Flush()
project.Documents.Remove(doc);
Session.Flush(); // this will delete that orphan

2 つ目は削除されたprojectインスタンスである可能性があり、明示的な更新呼び出しが必要です

// 2) updating evicted project instance
project.Documents.Remove(doc);
Session.Update(project);
//Session.Flush(); // Session session.FlushMode = FlushMode.Auto

に設定すると、この場合(のみ)、UPDATE ステートメントを使用してデータベースへの 1 回のトリップを減らし、参照をリセットしてからdoc.Project = nullDELETE を実行するのに役立ちます。

于 2012-11-27T07:22:43.543 に答える