DDD聚合根子关系NHibernate映射

时间:2012-08-02 18:16:50

标签: nhibernate domain-driven-design

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

Contact可以在Address汇总下引用CustomerCustomer对象具有唯一IDAddressContact对象具有本地ID,因此数据库中的主键为CustomerId和{ {1}}。

以下是简化类:

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 identity PK

CustomerId int not null PK,FK
AddressId int not null PK

当我尝试使用Fluent NHibernate映射我的实体时,我的问题出现了。由于CustomerId int not null PK,FK ContactId int not null PK AddressId int null FK 对象的复合键为AddressCustomerId,因此NHibernate不会在联系表中重用列AddressId。当我尝试保存聚合时,我得到一个例外,说有比参数更多的值。发生这种情况是因为Address对象具有复合ID,并且不与CustomerId对象共享CustomerId列。

我能看到解决此问题的唯一方法是在Contact表格中添加AddressCustomerId列,但现在我有一个重复的列Contact和{{1}是相同的值。反正有这种行为吗?

2 个答案:

答案 0 :(得分:1)

如果Address和Contact都没有Customer聚合之外的标识,则应将它们映射为组件集合。此外,客户地址和客户 - 联系关系是否需要双向?是否需要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);
                });
            });
    }
}

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

答案 1 :(得分:0)

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