每个类型的NHibernate表从现有父级持久化子级

每个类型的NHibernate表从现有父级持久化子级,nhibernate,inheritance,fluent-nhibernate,persistence,fluent-nhibernate-mapping,Nhibernate,Inheritance,Fluent Nhibernate,Persistence,Fluent Nhibernate Mapping,我有两个类,Member.cs和Customer.cs,并使用所描述的每种类型的表继承映射 这带来了同样的问题,但没有答案 Customer.cs public class Customer { } public class Member : Customer { public Member(Customer customer) { CreateFromCustomer(customer); } private void CreateFromC

我有两个类,
Member.cs
Customer.cs
,并使用所描述的每种类型的表继承映射

这带来了同样的问题,但没有答案

Customer.cs

public class Customer
{
}
public class Member : Customer
{
    public Member(Customer customer)
    {
        CreateFromCustomer(customer);
    }

    private void CreateFromCustomer(Customer customer)
    {
        // Here I assume I'll assign the Id so NHibernate wouldn't have to create a new Customer and know what Customer to be referred
        Id = customer.Id;
    }
}
public class CustomerMap : ClassMap<Customer>
{
    public CustomerMap()
    {
        Id(x => x.Id)
            .GeneratedBy.GuidComb();
    }
}
public class MemberMap : SubclassMap<Member>
{
    public MemberMap()
    {
        KeyColumn("Id");
    }
}
[Test]
public void CanAddCustomer()
{
    var customerRepo = /* blablabla */;

    using (var tx = NHibernateSessionManager.GetSession().BeginTransaction())
    {
        var customer = new Customer()

        customerRepo.RegisterCustomer(customer);

        tx.Commit();
    }

    using (var tx = NHibernateSessionManager.GetSession().BeginTransaction())
    {
        /* Get the persisted customer */
        var customer = customerRepo.GetCustomerByWhatever();

        var member = customerRepo.RegisterMember(new Member(customer));

        tx.Commit();
    }
}
Member.cs

public class Customer
{
}
public class Member : Customer
{
    public Member(Customer customer)
    {
        CreateFromCustomer(customer);
    }

    private void CreateFromCustomer(Customer customer)
    {
        // Here I assume I'll assign the Id so NHibernate wouldn't have to create a new Customer and know what Customer to be referred
        Id = customer.Id;
    }
}
public class CustomerMap : ClassMap<Customer>
{
    public CustomerMap()
    {
        Id(x => x.Id)
            .GeneratedBy.GuidComb();
    }
}
public class MemberMap : SubclassMap<Member>
{
    public MemberMap()
    {
        KeyColumn("Id");
    }
}
[Test]
public void CanAddCustomer()
{
    var customerRepo = /* blablabla */;

    using (var tx = NHibernateSessionManager.GetSession().BeginTransaction())
    {
        var customer = new Customer()

        customerRepo.RegisterCustomer(customer);

        tx.Commit();
    }

    using (var tx = NHibernateSessionManager.GetSession().BeginTransaction())
    {
        /* Get the persisted customer */
        var customer = customerRepo.GetCustomerByWhatever();

        var member = customerRepo.RegisterMember(new Member(customer));

        tx.Commit();
    }
}
CustomerMap.cs

public class Customer
{
}
public class Member : Customer
{
    public Member(Customer customer)
    {
        CreateFromCustomer(customer);
    }

    private void CreateFromCustomer(Customer customer)
    {
        // Here I assume I'll assign the Id so NHibernate wouldn't have to create a new Customer and know what Customer to be referred
        Id = customer.Id;
    }
}
public class CustomerMap : ClassMap<Customer>
{
    public CustomerMap()
    {
        Id(x => x.Id)
            .GeneratedBy.GuidComb();
    }
}
public class MemberMap : SubclassMap<Member>
{
    public MemberMap()
    {
        KeyColumn("Id");
    }
}
[Test]
public void CanAddCustomer()
{
    var customerRepo = /* blablabla */;

    using (var tx = NHibernateSessionManager.GetSession().BeginTransaction())
    {
        var customer = new Customer()

        customerRepo.RegisterCustomer(customer);

        tx.Commit();
    }

    using (var tx = NHibernateSessionManager.GetSession().BeginTransaction())
    {
        /* Get the persisted customer */
        var customer = customerRepo.GetCustomerByWhatever();

        var member = customerRepo.RegisterMember(new Member(customer));

        tx.Commit();
    }
}
我希望有:

1名客户和1名作为该客户子女的成员

相反,我有:

2个客户(1个是正确创建的,1个包含所有空列)和1个Id引用了所有空列的成员Customer

这是预期的行为吗

我理解如果我们想从一个临时父对象创建一个子对象,这是一个正确的行为

但是,如果我们要创建一个引用现有父对象的子对象呢

我提供的链接没有涵盖任何持久性示例,谷歌也没有。

简短回答 不,不可能将已持久化的对象“升级”到其子类。Nhibernate根本不支持这一点。这就是为什么您会看到两个客户和一个会员条目。这实际上是预期的行为,因为Nhibernate只是使用对象的新ID创建一个副本,而不是创建对成员的引用

所以基本上你可以做任何一件事

  • 将客户数据复制到会员,删除客户,保存会员
  • 使用不带子类的不同对象结构,其中成员是具有自己ID和对Customer的引用的不同表
  • 使用本机sql将行插入成员 例如: 你的课程可能是这样的

    public class Customer
    {
        public virtual Guid Id { get; set; }
        public virtual string Name { get; set; }
    }
    public class Member : Customer
    {
        public virtual string MemberSpecificProperty { get; set; }
    }
    
    基本上,成员可以具有其他属性,但也将具有与原因客户相同的属性

    public class CustomerMap : ClassMap<Customer>
    {
        public CustomerMap()
        {
            Id(x => x.Id)
                .GeneratedBy.GuidComb();
    
            Map(x => x.Name);
        }
    }
    
    这将在customer表中创建2个条目,在Member表中创建一行。所以这是意料之中的,因为我们创建了一个客户和一个成员

    现在,从客户A到会员的“升级”:

    using (var session = NHibernateSessionFactory.Current.OpenSession())
    {
        session.Save(new Customer()
        {
            Name ="Customer A"
        });
    
        session.Flush();
    }
    
    using (var session = NHibernateSessionFactory.Current.OpenSession())
    {
        var customer = session.Query<Customer>().FirstOrDefault();
        //var member = customer as Member;
        var member = new Member()
        {
            Name = customer.Name,
            MemberSpecificProperty = "something else"
        };
        session.Delete(customer);
        session.Save(member);
    
        session.Flush();
    }
    
    使用(var session=NHibernateSessionFactory.Current.OpenSession())
    {
    session.Save(新客户()
    {
    Name=“客户A”
    });
    session.Flush();
    }
    使用(var session=NHibernateSessionFactory.Current.OpenSession())
    {
    var customer=session.Query().FirstOrDefault();
    //var成员=作为成员的客户;
    var成员=新成员()
    {
    Name=customer.Name,
    MemberSpecificProperty=“其他内容”
    };
    删除(客户);
    会议.保存(成员);
    session.Flush();
    }
    
    我之前确实尝试过这种方法,但我有一些担心:关于Id引用,因为成员来自客户,所以他们有相同的Id生成策略,Generated.Guid说。当我从现有的Customer.Id中分配Member.Id时会发生什么情况?该Id是持久化的,还是生成了新的Id?我关心的是,如果客户需要在这里安装IList,该怎么办。而且真正删除一个客户也很麻烦,因为我基本上喜欢Cascade。所有的策略都是为了持久化新的实体。但是如果有必要,我愿意改为Cascade.SaveUpdate。正如我所写的,您不能重用已存储的ID为A的客户来创建ID为A的成员,nHibernate将生成一个新的ID B,并将客户+成员行存储在ID为B的数据库中。那么,当存在引用现有客户的其他数据时,如何解决该问题?它们也应该被重新创造吗?对整个对象图进行重新创建需要大量的工作。@SamuelAdam是的,正如我所写的,重新创建、使用不同的对象策略或使用本机sql。如果这是应用程序中常见的场景,我建议使用不同的策略。意思是不让成员从客户继承。。。简单地建立一对一的关系就可以了,因为这意味着每个客户可能都必须有一个成员