我见过两种类型的实体,如:
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;}
}
我认为第二种方法更轻巧,只有在需要时才能获得相关数据; 你认为哪一个更好?
答案 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在域模型中映射外键。