4

没有做任何事情我有互相引用作为一个一对多的关系,下面定义了两个简单的类:功能NHibernate - 级联全部删除孤儿上删除

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(项目),反映出我的数据库中正确的改变,但是如果我从与项目有关的文档列表中删除文件并调用session.Save(项目)删除的文件永远不会从数据库中删除。

任何想法为什么一切都会工作,除了删除?

编辑: 我的MVC 4项目设置与功能NHibernate如下:

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

我在定义2个操作我ProjectsController如下:

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属性的action中的project.Documents中,repository.Update(project)成功地将具有正确外键引用的行添加到项目中。当我删除文档时,这只会失败。

回答

2

级联设置似乎是正确的。提到可能是其他地方的问题:

但是如果我是从一个项目

怀疑给我相关的文档列表中删除文档

是一个会话冲洗模式,或缺少显式调用更新先前分离的父实体Project。保证:

首先,Flush()被调用。如果project实例仍保留在Session,中,则可以更改刷新的默认行为。 (例如session.FlushMode = FlushMode.Never;Commit而没有交易...)

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

第二个可能是驱逐project例如,需要显性更新呼叫

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

设置会在这种情况下(只)有助于减少一次旅行数据库与UPDATE语句,重置对doc.Project = null的引用,然后执行DELETE。

+0

我已经更新了我的问题,希望能提供一些更有用的信息。我无法得到你的任何建议工作。你有什么建议吗? –

+0

作为一个问题,我看到在'HttpPost'中,MVC运行时为您实例化新的Project实例并将其与FORM值绑定。我建议通过'Id'从NHibernate会话中获取()一个实例,然后绑定它。你的情况有可能吗?因为现在NHibernate提供了**新**集合,没有关于删除项目的信息... –

+0

你有什么建议如何做到这一点?如果我尝试'项目实体= repository.FindById(project.Id); entity = project; repository.Update(entity);'我得到错误:**具有相同标识符值的不同对象已经与会话相关联:1,实体** –

2

您是否尝试过将.Inverse添加到您的HasMany映射中?我不熟悉Not.KeyNullable。我认为这不是必要的。