2016-01-21 11 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 в моем классе Customer. Можно ли достичь в Нюбернате? Я пробовал 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?

Edit: Вот как она работает с 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(); 
     } 

Имея клиентов и соответствующей ActivityLog в БД, удаляет как

+0

Как это работает в EF? – ngm

+0

Добавлено редактирование, как это работает для меня в EF –

ответ

0

Я хотел бы быть в состоянии удалить клиента и все соответствующие ActivityLog элементы , по телефону

session.Delete(customer); 

То, что я не хочу, это иметь собственность Li st Logs in мой класс клиентов. Можно ли достичь в Нюбернате?

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