在实体,优点和缺点中只放置FK的密钥类型(id)或类类型

时间:2010-09-27 09:19:56

标签: c# .net nhibernate entity-framework

我见过两种类型的实体,如:

public class Person
{
    public int Id {get;set;}
    public string Name {get;set;}
    public Country Country {get;set;}
}

并且像这样:

public class Person
{
    public int Id {get;set;}
    public string Name {get;set;}
    public int CountryId {get;set;}
}

我认为第二种方法更轻巧,只有在需要时才能获得相关数据; 你认为哪一个更好?

6 个答案:

答案 0 :(得分:1)

这取决于你想要什么。如果您只想获得国家/地区的ID,请转到第二个选项。如果您确实想要使用导航属性和/或延迟加载,那么请选择第一个选项。

就个人而言,我使用实体框架并结合选项一和二:

public class Person
{
    public int Id {get;set;}
    public string Name {get;set;}
    public int CountryId {get;set;}
    public Country Country {get;set;}
}

所以我可以选择从我的存储库返回数据。这也意味着当我来保存时,我可以只填充实际的值类型属性,而不必加载国家/地区对象并将其分配给此人。

答案 1 :(得分:1)

从面值来看,第一个是富域模型的示例,第二个是数据驱动方法。允许丰富的域模型是ORM的主要优势之一。

我要包括CountryId(代替国家或者除此之外)的唯一原因是针对某些非常具体的性能问题进行优化。即便如此,我会三思而后行。优化是你在初始设计阶段不应该考虑太多的东西。 Person.Country.Id怎么了? (假设你需要id,而不仅仅是基础设施)。

如果您从性能优化以外的任何角度来看这个问题,那么您可能通过在域模型中包含“外键”来采取错误的方法。第一次使用NHibernate时,我遇到了同样的问题,来自ADO类型的背景。我几乎肯定会选择第一个例子。

答案 2 :(得分:1)

有两个注意事项,平台和流量,概述如下......

所有在Microsoft平台

在多层解决方案中,最终客户端是Silverlight,您将通过RIA服务共享生成的代码,或者您拥有带有WCF RIA服务的WPF客户端,第一个解决方案为您提供更好的设计。

非Microsoft终端客户端

如果您的终端客户端是非Microsoft客户端,如Flex / Flash,Java或任何基于ajax的智能客户端,那么第一个模型将无用,因为它需要跟踪自身(自我跟踪对象)。这里首选第二种模式。

低流量应用

如果网络流量不是很大问题而且你的软件设计更重要,或者你有高度可扩展的中间轮胎用于缓存等,比如App Fabric等,那么第一个解决方案很好,它会给你更好的设计。

高流量应用

第一个模型将序列化所需的更多数据,这在高流量应用程序中可能是一个真正的性能问题。因此,在这种情况下,第二个模型将更好地工作,因为只有当用户请求更多的引用数据时,才会加载它。

这是“更好的设计”与“更好的性能”之间的权衡问题,需要根据上述参数进行选择,根据项目的复杂程度,团队规模,文档等,可以有更多参数。

答案 3 :(得分:1)

好问题!对我来说

public List<Person> GetPersonsLivingIn(int countryId) {
  return ObjectContext.Persons.Where(x => x.CountryId == countryId).ToList();
}

看起来它的工作原理是这样,而不知道ORM中可能存在的x => x.Country == country工作的所有魔术(漏洞)抽象。我来自Linq2Sql,在传递在不同对象上下文中创建的对象时,我遇到了第一个问题。

但我会像GenericTypeTea那样说并包含id和navigation属性。毕竟,在某些时候你需要一个可导航的对象图。这样你仍然可以做到

public List<Person> GetPersonsLivingIn(Country country) {
  return ObjectContext.Persons.Where(x => x.CountryId == country.CountryId).ToList();
}

它具有更多的OO感觉界面,但看起来它仍然没有魔法。

答案 4 :(得分:1)

除了一些奇怪的边缘情况,第二种设计没有充分的理由。

它们同样轻量级(默认情况下引用是延迟加载的),但第二个不提供导航功能,这会限制查询并使其复杂化。

答案 5 :(得分:1)

<强> STOP!

在NHibernate中, NO 需要在域模型中指定外键,即使出于性能原因也是如此。

假设您启用了延迟加载(默认情况下已启用),请调用:

int countryId = person.Country.Id;

... 不会招致数据库点击以检索国家/地区实体。 NHibernate将返回客户的动态代理,而不是实际的客户。由于代理,数据库命中只会在首次访问您的Customer实体上的Property时发生,但NHibernate足够聪明地意识到'person.Country.Id'与访问您的Person中的客户ID外键相同表,无论如何都会加载。

但是,以下代码:

string countryName = person.Country.Name;

...将命中数据库,对'Name'属性的调用将加载整个Customer实例。

此行为假定您已按如此设置映射:

<many-to-one name="Country" class="Country" column="Country_ID" lazy="proxy" />

(请注意,lazy =“proxy”是默认值。)

简单地说,没有必要使用NHibernate在域模型中映射外键。