2016-01-21 72 views
1

假设我有以下的模型NHibernate的无父对象有属性中删除子集合

public class Customer 
{ 
    public virtual Guid Id { get; set; } 
    public virtual string Name { get; set; } 
} 

public class ActivityLog 
{ 
    public virtual Guid Id { get; set; } 
    public virtual Guid CustomerId { get; set; } 
    public virtual Customer Customer { get; set; } 
    public virtual DateTime ActivityDate { get; set; } 
} 

我希望能够删除客户和所有相应ActivityLog项目,通过调用

session.Delete(customer); 

我不想在我的客户类中拥有 List<ActivityLog> Logs属性。是否可以在Nhibernate中实现?我试过EF,它在那里工作,但在HN获取参考约束例外。

我的映射:

public class CustomerMap : ClassMapping<Customer> 
{ 
    public CustomerMap() 
    { 
     Id(x => x.Id, map => map.Generator(Generators.GuidComb)); 
     Property(x => x.Name); 

    } 
} 

public class ActivityLogMap : ClassMapping<ActivityLog> 
{ 
    public ActivityLogMap() 
    { 
     Id(x => x.Id, map => map.Generator(Generators.GuidComb)); 
     Property(x => x.ActivityDate); 
     ManyToOne(x => x.Customer, mapping => 
     { 

      mapping.Class(typeof(Customer)); 
      mapping.Column("CustomerId"); 

     }); 
    } 
} 

也许可能有一些扩展钩子和检查映射和NHibernate的做手工?

编辑:它在这里是如何使用EF

public class CustomerEFMap : EntityTypeConfiguration<Customer> 
{ 
    public CustomerEFMap() 
    { 
     ToTable("Customer"); 
     HasKey(x => x.Id); 
     Property(x => x.Name); 
    } 
} 

public class ActivityLogEFMap : EntityTypeConfiguration<ActivityLog> 
{ 
    public ActivityLogEFMap() 
    { 
     ToTable("ActivityLog"); 
     HasKey(x => x.Id); 
     HasRequired(x => x.Customer).WithMany().HasForeignKey(x => x.CustomerId); 
    } 
} 

using (var context = new ObjectContext()) 
     { 
      var customer = context.Set<Customer>().Find(id); 
      context.Set<Customer>().Remove(customer); 

      context.SaveChanges(); 
     } 

拥有客户和DB相应ActivityLog,同时删除

+0

它在EF中如何工作? – ngm

+0

增加了编辑,它如何在EF –

回答

0

我希望能够删除客户和所有相应 ActivityLog项目,通过致电

session.Delete(customer); 

我不想要的是一个物业李st登录我的客户类 。是否可以在Nhibernate中实现?

NO。不可能,不打算,不支持。 NHibernate是ORM工具,将/可以关心关系。没有关系,没有在意(无级联)

但是,我们能够始终隐藏列表属性通过使protected

public class Customer 
{ 
    public virtual Guid Id { get; set; } 
    public virtual string Name { get; set; } 
    // HIDDEN in fact from consumers, managed by NHibernate 
    protected virtual IList<ActivitLog> { get; set; } 
} 

cascade到位的映射 - 会做什么是必须的。

+0

中为我工作好吧,EF也是ORM,但我可以在那里实现它。我想开发一些类似于插件系统的东西,所以我不想在开发新插件时修改客户端 –

+0

您对NHibernate提出的问题不是关于EF,我的答案是针对NHibernate –

0

作为Radim Köhler states,我不认为有任何简单的方式映射级联的行为,而没有实际的关系。但是,因为你的理由是基于插件的架构,所以使用部分类可能是你需要的。

您可以将ActivityLog s的集合作为受保护集合作为插件DLL中部分类的一部分。如果您的映射然后映射集合,删除Customer将删除ActivityLog

以下示例应该可以工作 - 请注意,我正在使用FluentNhibernate进行映射。

此解决方案确实依赖于您能够将Customer类标记为部分。

using FluentAssertions; 
using FluentNHibernate; 
using FluentNHibernate.Cfg; 
using FluentNHibernate.Cfg.Db; 
using FluentNHibernate.Mapping; 
using NHibernate.Linq; 
using NHibernate.Tool.hbm2ddl; 
using NUnit.Framework; 
using System; 
using System.Collections.Generic; 

namespace MapTest 
{ 
    public partial class Customer 
    { 
     public virtual Guid Id { get; set; } 
     public virtual string Name { get; set; } 
    } 

    public class ActivityLog 
    { 
     public virtual Guid Id { get; set; } 
     public virtual Customer Customer { get; set; } 
     public virtual DateTime ActivityDate { get; set; } 
    } 

    public class CustomerMap : ClassMap<Customer> 
    { 
     public CustomerMap() 
     { 
      Id(x => x.Id).GeneratedBy.Guid(); 
      Map(x => x.Name); 

      HasMany<ActivityLog>(Reveal.Member<Customer>("ActivityLogs")).Cascade.All(); 
     } 
    } 

    public class ActivityLogMap : ClassMap<ActivityLog> 
    { 
     public ActivityLogMap() 
     { 
      Id(x => x.Id).GeneratedBy.Guid(); 
      Map(x => x.ActivityDate); 
      References(x => x.Customer); 
     } 
    } 

    // Part of your plugin DLL 
    public partial class Customer 
    { 
     protected virtual IList<ActivityLog> ActivityLogs { get; set; } 
    } 

    [TestFixture] 
    public class PartialClassCascade 
    { 
     [Test] 
     public void RunOnceToSetupDb() 
     { 
      Fluently.Configure() 
       .Database(MsSqlConfiguration.MsSql2012.ConnectionString(@"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=MapTest;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False")) 
       .Mappings(m => m.FluentMappings.AddFromAssemblyOf<CustomerMap>()) 
       .ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(false, true)) 
       .BuildSessionFactory(); 
     } 

     [Test] 
     public void DeletingCustomerWithActivityLogs() 
     { 
      var sessionFactory = Fluently.Configure() 
       .Database(MsSqlConfiguration.MsSql2012.ConnectionString(@"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=MapTest;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False")) 
       .Mappings(m => m.FluentMappings.AddFromAssemblyOf<CustomerMap>()) 
       .BuildSessionFactory(); 

      using (var session = sessionFactory.OpenSession()) 
      using (var tx = session.BeginTransaction()) 
      { 
       session.CreateQuery("delete ActivityLog a").ExecuteUpdate(); 
       session.CreateQuery("delete Customer c").ExecuteUpdate(); 

       tx.Commit(); 
      } 

      var homerId = default(Guid); 
      using (var session = sessionFactory.OpenSession()) 
      using (var tx = session.BeginTransaction()) 
      { 
       var homer = new Customer 
       { 
        Name = "Homer Simpson" 
       }; 
       var monty = new Customer 
       { 
        Name = "Monty Burns" 
       }; 
       session.Save(homer); 
       session.Save(monty); 

       homerId = homer.Id; 

       var activityLog1 = new ActivityLog 
       { 
        Customer = homer, 
        ActivityDate = DateTime.Now, 
       }; 
       var activityLog2 = new ActivityLog 
       { 
        Customer = monty, 
        ActivityDate = DateTime.Now.AddDays(1), 
       }; 
       session.Save(activityLog1); 
       session.Save(activityLog2); 

       tx.Commit(); 
      } 

      using (var session = sessionFactory.OpenSession()) 
      using (var tx = session.BeginTransaction()) 
      { 
       var customer = session.Get<Customer>(homerId); 
       session.Delete(customer); 

       tx.Commit(); 
      } 

      using (var session = sessionFactory.OpenSession()) 
      using (var tx = session.BeginTransaction()) 
      { 
       var customers = session.Query<Customer>(); 
       var activityLogs = session.Query<ActivityLog>(); 

       customers.Should().HaveCount(1); 
       activityLogs.Should().HaveCount(1); 
      } 
     } 
    } 
} 
+0

您无法在单独的DLL中定义部分类 –

+0

哦,我其实并不知道。你是正确的,但:http://stackoverflow.com/q/3858649/206297。有可能遵循类似的策略,但在独立的DLL中使用继承。我不确定它是否会在你的情况下工作。 – ngm