2010-09-02 71 views
0

假设我有以下表格:NHibernate:通过PK以外的东西链接集合

Company   Person     Address 
---------------------------------------------------------------------------- 
Id (PK)   Id (PK)    Id (PK) 
Name    CompanyId (FK)   CompanyId (FK) 
        AccessType    AddressType 

对应于以下C#.NET类:

class Company 
{ 
    int Id; 
    List<Person> Employees; 
    List<Address> Addresses; 
} 

class Person 
{ 
    int Id; 
    List<Address> CompanyAddresses; 
} 

class Address 
{ 
    int Id; 
    // ... 
} 

使用NHibernate在Company类上映射Person + Address集合非常容易:

<class name="Company" table="Company"> 
    <id name="Id" column="Id" /> 
    <set name="Employees" table="Person"> 
     <key column="CompanyId" /> 
     <one-to-many class="Person" /> 
    </set> 
    <set name="Addresses" table="Address"> 
     <key column="CompanyId" /> 
     <one-to-many class="Address" /> 
    </set> 
</class> 

<class name="Person" table="Person"> 
    <id name="Id" column="Id" /> 
</class> 

<class name="Address" table="Address"> 
    <id name="Id" column="Id" /> 
</class> 

我的问题是,如何将地址也映射到Person类?这个想法是,公司有一个人员(员工)和地址(站点)的列表,但公司地址也可以从公司的员工中查找。 (我知道,有点奇怪和非正统,但只是和我一起玩)。

通常,我可以通过在Person类映射上定义类似下面的内容来实现:

<set name="CompanyAddresses" table="Address"> 
    <key column="CompanyId" property-ref="CompanyId" /> 
</set> 

...但是Person(.NET)对象没有为property-ref声明实现CompanyId属性拿水(我们不喜欢它)。

如何通过NHibernate在Person对象中保留一组地址,其中Person :: CompanyId = Address :: CompanyId?

谢谢你们。 :)

编辑

这实际上只是做了像迭戈建议的Person.Company.Addresses映射,但遗憾的是,这不会完全奏效,因为公司会有一个地址列表,每个与公司相关联的人员只会拥有这些地址的子集。

我已经更新了上面的表模式。可以想象,如果Person具有AccessType = ENGINEER,那么只有AddressType = ENGINEERING Addresses将保留在其中(除了CompanyId = CompanyId)。

回答

1

如果你打算存储一个人的地址,我认为你需要在地址表中有一些东西来链接回人员表。

所以,你既可以添加PERSONID列,并用它作为FK对于这涉及到一个人

Address 
---------- 
Id (PK) 
PersonID (FK - nullable) 
CompanyID (FK - nullable) 

或者你可以有一个鉴别列地址,在这种情况下,你的地址表看起来是这样的:

Address 
---------- 
Id (PK) 
Owner (Discriminator, eg either "Person" or "Company") 
OwnerID (FK) 

最自然的方式(即我所知道的)的映射是那么as a Table per Class Hierarchy,虽然涉及具有PersonAddress和公司地址子类。

+0

我认为,鉴别列可能有一定的潜力。 :)我会研究这一点,让你知道如何平息。 – 2010-09-02 21:44:34

1

您不应该尝试直接映射它。

由于一个人有一个公司(它在桌面上,我没有看到它在你的映射中,但它应该在那里),获取地址的最简单方法是person.Company.Addresses

如果需要,您可以将其包装在CompanyAddresses属性中,该属性只是代表Company.Addresses

更新:您可以轻松地过滤那些地址,但该列表将是只读的:

public IEnumerable<Address> CompanyAddresses 
{ 
    get { return Company.Addresses.Where(a => a.AddressType == AccessType); } 
} 
+0

是的,我就是这么想的---除了这里真正发生的事情是,虽然公司有一个Person集合,但是链接的Person(s)另一方面只有一个地址子集他们的母公司有(认为它是一个公司有很多网站,但只有一些员工可以访问)。因此,Person.Company.Addresses不完全正常工作。 :(我将编辑上述问题 – 2010-09-02 21:35:09

+0

根据您的编辑添加修复 – 2010-09-02 23:03:15