代码之家  ›  专栏  ›  技术社区  ›  awilinsk

DDD聚合根-子关系NHibernate映射

  •  2
  • awilinsk  · 技术社区  · 13 年前

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

    A. 联系 可以引用 住址 顾客 总数的这个 顾客 对象具有唯一 ID 以及 住址 联系 对象具有本地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 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映射我的实体时,我的问题就来了。因为 住址 对象的复合键为 客户ID 地址Id ,NHibernate不会重复使用该柱 客户ID 在联系人表中。当我试图保存聚合时,我得到一个异常,说值比参数多。发生这种情况是因为Address对象具有复合ID,并且不共享 客户ID 具有的列 联系 对象

    我能看到的唯一方法是添加 AddressCustomerId 中的列 联系 表,但现在我有一个重复的列作为 客户ID 地址客户ID 是相同的值。这种行为到底有没有?

    2 回复  |  直到 13 年前
        1
  •  1
  •   eulerfx    13 年前

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

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

        2
  •  1
  •   awilinsk    13 年前

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