DDD聚合根-子关系NHibernate映射

DDD聚合根-子关系NHibernate映射,nhibernate,domain-driven-design,Nhibernate,Domain Driven Design,我试图遵循总体设计原则,并提出了一个需要帮助的情况。我的聚合根是一个Customer对象。Customer对象具有Address对象的子集合和Contact对象的子集合 联系人可以在客户聚合下引用地址。Customer对象具有唯一的ID,Address和Contact对象具有本地ID,因此数据库中的主键应该是CustomerId和AddressId 以下是简化类: public class Customer : AggregateRoot { public virtual int Cus

我试图遵循总体设计原则,并提出了一个需要帮助的情况。我的聚合根是一个
Customer
对象。
Customer
对象具有
Address
对象的子集合和
Contact
对象的子集合

联系人
可以在
客户
聚合下引用
地址
Customer
对象具有唯一的
ID
Address
Contact
对象具有本地ID,因此数据库中的主键应该是
CustomerId
AddressId

以下是简化类:

public class Customer : AggregateRoot {
    public virtual int CustomerId { get; protected set; }
    public virtual IList<Address> Addresses { get; protected set; }
    public virtual IList<Contact> Contacts { get; protected set; }
}
public class Address : Entity {
    public Address(Customer customer, int addressId) {
        this.Customer = customer;
        this.AddressId = addressId;
    }

    public virtual Customer Customer { get; protected set; }
    public virtual int AddressId { get; protected set; }
}
public class Contact : Entity {
    public Contact(Customer customer, int contactId) {
        this.Customer = customer;
        this.ContactId = contactId;
    }

    public virtual Customer Customer { get; protected set; }
    public virtual int ContactId { get; protected set; }
    public virtual Address Address { get; set; }
}
地址

CustomerId int not null PK,FK
AddressId int not null PK
联系方式

CustomerId int not null PK,FK
ContactId int not null PK
AddressId int null FK
当我试图用流畅的NHibernate映射我的实体时,我的问题来了。因为
Address
对象有一个组合键
CustomerId
AddressId
,所以NHibernate不会重用联系人表中的列
CustomerId
。当我试图保存聚合时,我得到一个异常,即值多于参数。这是因为地址对象具有复合ID,并且不与
联系人
对象共享
CustomerId


解决这个问题的唯一方法是在
Contact
表中添加一个
AddressCustomerId
列,但现在我有一个重复的列,因为
CustomerId
AddressCustomerId
是相同的值。是否存在这种行为?

如果地址和联系人在客户聚合之外都没有标识,则应将其映射为组件集合。此外,客户地址和客户联系关系是否需要是双向的?是否需要addressId和contactId?如果模型简化,这将起作用:

public class Customer
{
    public virtual int CustomerId { get; protected set; }
    public virtual IList<Address> Addresses { get; protected set; }
    public virtual IList<Contact> Contacts { get; protected set; }
}

public class Address
{
    public string Street1 { get; private set; }
    public string Street2 { get; private set; }
    public string City { get; private set; }
    public string Region { get; private set; }
}

public class Contact
{
    public string Name { get; private set; }
    public string Email { get; private set; }
    public virtual Address Address { get; set; }
}

public class CustomerMap : FluentNHibernate.Mapping.ClassMap<Customer>
{
    public CustomerMap()
    {
        Table("Customers");
        Id(x => x.CustomerId);
        HasMany(x => x.Addresses)
            .Table("CustomerAddresses")
            .KeyColumn("CustomerId")
            .Component(m =>
            {
                m.Map(x => x.Street1);
                m.Map(x => x.Street1);
                m.Map(x => x.City);
            });
        HasMany(x => x.Contacts)
            .Table("CustomerContacts")
            .KeyColumn("CustomerId")
            .Component(m =>
            {
                m.Map(x => x.Name);
                m.Map(x => x.Email);
                m.Component(x => x.Address, ma =>
                {
                    ma.Map(x => x.Street1);
                });
            });
    }
}
公共类客户
{
公共虚拟int CustomerId{get;protected set;}
公共虚拟IList地址{get;protected set;}
公共虚拟IList联系人{get;protected set;}
}
公共课堂演讲
{
公共字符串Street1{get;private set;}
公共字符串Street2{get;private set;}
公共字符串City{get;private set;}
公共字符串区域{get;private set;}
}
公共类联系人
{
公共字符串名称{get;private set;}
公共字符串电子邮件{get;private set;}
公共虚拟地址{get;set;}
}
公共类CustomerMap:FluentNHibernate.Mapping.ClassMap
{
公共客户映射()
{
表(“客户”);
Id(x=>x.CustomerId);
HasMany(x=>x.address)
.表格(“客户地址”)
.KeyColumn(“客户ID”)
.组件(m=>
{
m、 地图(x=>x.Street1);
m、 地图(x=>x.Street1);
m、 地图(x=>x.City);
});
有许多(x=>x个联系人)
.表格(“客户联系人”)
.KeyColumn(“客户ID”)
.组件(m=>
{
m、 Map(x=>x.Name);
m、 Map(x=>x.Email);
m、 组件(x=>x.地址,ma=>
{
ma.地图(x=>x.Street1);
});
});
}
}

在映射中,地址和联系人集合被映射为组件。这意味着它们不需要有自己的标识,因此不需要单独的映射类。然而,在这个模型中,联系人的地址将与联系人数据本身存储在同一行中,我认为这是一个很好的模型(与更规范化的模型相反)。

据我所知,在NHibernate中无法共享列。我最终选择了我已经使用了几年的解决方案。我使用GUID作为NHibernate的ID,并使用int代理键进行查询。这个解决方案对我来说效果很好,但我只是想减少数据库中增加的一些浪费。

我之所以这样设计它,是因为我可以从数据库中查询个人联系人,而无需先加载客户对象。地址和联系人是实体,应具有本地标识符。客户也可以有许多独立于联系人的地址,客户也可以有许多独立于地址的联系人。我对DDD非常陌生,但我认为实体可以在聚合根中引用其他实体,这意味着实体需要一个本地标识。
public class Customer
{
    public virtual int CustomerId { get; protected set; }
    public virtual IList<Address> Addresses { get; protected set; }
    public virtual IList<Contact> Contacts { get; protected set; }
}

public class Address
{
    public string Street1 { get; private set; }
    public string Street2 { get; private set; }
    public string City { get; private set; }
    public string Region { get; private set; }
}

public class Contact
{
    public string Name { get; private set; }
    public string Email { get; private set; }
    public virtual Address Address { get; set; }
}

public class CustomerMap : FluentNHibernate.Mapping.ClassMap<Customer>
{
    public CustomerMap()
    {
        Table("Customers");
        Id(x => x.CustomerId);
        HasMany(x => x.Addresses)
            .Table("CustomerAddresses")
            .KeyColumn("CustomerId")
            .Component(m =>
            {
                m.Map(x => x.Street1);
                m.Map(x => x.Street1);
                m.Map(x => x.City);
            });
        HasMany(x => x.Contacts)
            .Table("CustomerContacts")
            .KeyColumn("CustomerId")
            .Component(m =>
            {
                m.Map(x => x.Name);
                m.Map(x => x.Email);
                m.Component(x => x.Address, ma =>
                {
                    ma.Map(x => x.Street1);
                });
            });
    }
}