每种类型的NHibernate表从现有父级继承子级

时间:2013-10-15 17:46:04

标签: nhibernate inheritance fluent-nhibernate persistence fluent-nhibernate-mapping

我有2个类,Member.csCustomer.cs,并使用每个类型的表继承映射here

question提出了同样的问题,但没有回答。

Customer.cs

public class Customer
{
}

Member.cs

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

CustomerMap.cs

public class CustomerMap : ClassMap<Customer>
{
    public CustomerMap()
    {
        Id(x => x.Id)
            .GeneratedBy.GuidComb();
    }
}

MemberMap.cs

public class MemberMap : SubclassMap<Member>
{
    public MemberMap()
    {
        KeyColumn("Id");
    }
}

我尝试了几个测试用例:

Test1.cs

[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。

这是预期的行为吗?

我理解如果我们想要从瞬态父对象创建子对象,这是正确的行为。

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

我提供的链接并未涵盖任何持久性示例,也没有使用Google搜索。

1 个答案:

答案 0 :(得分:2)

简答

不,不可能将已经持久化的对象“升级”到其子类。 Nhibernate根本不支持这个。这就是为什么你看到2个客户和一个成员条目。这实际上是预期的行为,因为Nhibernate只是创建一个带有对象新ID的副本,而不是创建对Member的引用...

所以基本上你可以做任何一次

  1. 将客户数据复制到会员,删除客户并保存会员
  2. 使用不带子类的不同对象结构,其中Member是一个不同的表,其中包含自己的ID和对Customer的引用
  3. 使用本机sql将行插入Member ...
  4. 一些例子:

    您的课程可能如下所示

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

    对于子类,您只需要映射其他属性!

    public class MemberMap : SubclassMap<Member>
    {
        public MemberMap()
        {
            Map(x => x.MemberSpecificProperty);
        }
    }
    

    测试它

    {
        session.Save(new Customer()
        {
            Name ="Customer A"
        });
    
        session.Save(new Member()
        {
            Name = "Customer B",
            MemberSpecificProperty = "something else"
        });
    
        session.Flush();
    }
    

    这将在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();
    }