2

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

AContact可以引用聚合Address下的a。CustomerCustomer对象具有唯一性ID,而AddressandContact对象具有本地 id,因此数据库中的主键是CustomerIdand 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

接触

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

当我尝试使用 Fluent NHibernate 映射我的实体时,我的问题就出现了。因为Address对象有一个复合键CustomerIdand AddressId,NHibernate 不会重用CustomerId联系人表中的列。当我尝试保存聚合时,我得到一个异常,说值多于参数。发生这种情况是因为 Address 对象具有复合 ID,并且不CustomerId与对象共享列Contact

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

4

2 回答 2

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

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

于 2012-08-03T04:27:24.180 回答
0

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

于 2012-08-13T11:27:23.833 回答