1

我有 2 个类,Member.cs并使用此处Customer.cs描述的每个类型的表继承映射。

这个问题提出了同样的问题,但没有答案。

客户.cs

public class Customer
{
}

会员.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;
    }
}

客户地图.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");
    }
}

我尝试了几个测试用例:

测试1.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 引用所有空列客户的成员。

这是预期的行为吗?

我知道如果我们想从瞬态父对象创建一个子对象,这是一个正确的行为。

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

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

4

1 回答 1

2

简答

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

所以基本上你可以做

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

一些例子:

你的课程可能看起来像这样

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

基本上,Member 可以具有其他属性,但也将具有与 Customer of Cause 相同的属性。

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

这将在客户表中创建 2 个条目,并在成员表中创建一行。所以这符合预期,因为我们创建了一个客户和一个成员......

现在从客户 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();
}
于 2013-10-15T20:28:17.540 回答