2012-08-02 96 views
2

我想遵循总体设计原则,并想出了我需要帮助的情况。我的聚合根是一个Customer对象。 Customer对象具有Address对象的子集合和Contact对象的子集合。DDD聚合根子关系NHibernate映射

A Contact可以参考Customer集合下的AddressCustomer对象具有唯一的ID,而对象AddressContact具有本地ID,因此数据库中的主键为CustomerIdAddressId

这里是简化类:

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 

当我试图映射我与功能NHibernate实体我的问题来了。由于Address对象具有CustomerIdAddressId的组合键,因此NHibernate不会重复使用联系人表中的列CustomerId。当我尝试保存聚集时,我收到一个异常,说有更多的值比有参数。发生这种情况的原因是地址对象具有复合ID,并且不与Contact对象共享CustomerId列。

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

回答

0

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

1

如果地址和联系人都不具有客户聚合之外的身份,则应将其映射为组件集合。另外,是否需要客户地址和客户 - 联系人关系是双向的?是否需要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); 
       }); 
      }); 
    } 
} 

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

+0

我按照自己的方式设计它的原因是因为我可以从数据库中查询单个联系人,而无需首先加载Customer对象。地址和联系人是实体,应具有本地标识符。客户可以拥有多个独立于联系人的地址,并且客户可以拥有多个独立于该地址的联系人。我对DDD相当陌生,但我认为实体可以引用聚合根内的其他实体,这意味着实体需要本地身份。 – awilinsk 2012-08-03 11:10:47