2010-09-27 69 views
3

我见过2种类型的实体的实体,利弊类类型FK,像这样:把刚才的密钥类型(ID)或

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;} 
} 

我认为第二个方法是更轻便,你只有当你需要的相关数据;
你觉得哪一个更好?

回答

1

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

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

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

所以我有一个选择,当谈到从我的仓库返回数据。这也意味着,当我来救,我可以填充,而不必加载国家对象,并将其分配给个人的实际值类型的属性。

1

从表面,第一个是一个丰富的域模型的一个例子,第二个是数据驱动的方法。允许丰富的域模型是ORM的主要优点之一。

我将包括CountryId(或者代替国家或除此之外)的唯一原因将用于优化某些非常具体的性能问题。即使这样,我也会考虑三次。优化是你在初始设计阶段不应该考虑太多的问题。 Person.Country.Id有什么问题? (假设你完全需要这个id,而不仅仅是基础设施)。

如果是从比性能优化其他任何角度看这一点,那么你可能通过在你的领域模型“外键”采取错误的做法。首次使用来自ADO类型背景的NHibernate时,我遇到了同样的问题。我几乎肯定会与第一个例子。

1

有两个方面的考虑,平台和流量,概述如下...

所有微软平台

在多层次的解决方案,在最终客户是Silverlight和你要分享你的生成代码通过RIA服务,或者你有WCF RIA服务的WPF客户端,第一种解决方案为你提供更好的设计。

非Microsoft最终客户

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

低流量的应用

如果网络流量是没有太大问题的,你的软件设计,更重要的,还是你有高度可扩展的中间轮胎,高速缓存等,例如App面料等,首先解决好一个这会给你更好的设计。

高流量应用

第一个模型序列化更多的数据,然后根据需要,并且能够在高流量应用的真正的性能问题。所以在这种情况下,第二种模式会更好,因为只有当用户请求更多的引用数据时,才会加载它。

这是在“更好的设计”和“更好的性能”之间的一个折衷问题,它需要根据上面提到的参数进行选择,根据项目的复杂程度,团队规模,文档和更多参数。

1

好问题!对我来说

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

只是看起来像它这样工作,无需了解所有的魔法(泄漏)的抽象可能存在的ORM,这将使x => x.Country == country工作。我来自Linq2Sql,当传递在不同的对象上下文中创建的对象时,我遇到了第一个问题。

但我会像GenericTypeTea说的那样做,并且包括id和导航属性。毕竟,你会希望在某个时候有一个可导航的对象图。这样你仍然可以制作更多OO感觉的界面,但仍然看起来像没有魔法一样工作。

+0

你称之为“魔术”的东西是ORM的核心。不使用它会创建一个贫血域模型,这是一种ORM反模式(IOW,如果您不使用它的功能,为什么要使用ORM?) – 2010-09-27 15:01:19

+0

感谢您的评论。从我的角度来看,在方法接口中暴露实体对象会给方法开发者带来一个问题:实体是否来自同一个对象上下文?我可以重新附加到我自己的吗?实体中加载了什么部分的对象图?我可以延迟加载实体的其他部分/是实体的对象上下文还活着吗? ORM增加了很多复杂性,我已经几次将我的手指烧在我认为可行的事情上,但没有。 – Andreas 2010-09-27 16:29:10

+0

您描述的所有问题都来自错误的会话管理。我并不是说每个人都能够直观地掌握基本概念,但是汽车的比喻应该已经到位。 – 2010-09-27 18:28:43

1

除了在一些奇怪的边缘情况下,第二种设计没有很好的理由。

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

1

停止!

在NHibernate中,有NO需要在你的领域模型指定外键,即使不是出于性能的考虑。

假设你有懒加载启用(它是默认启用),称:

int countryId = person.Country.Id; 

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

但是,下面的代码:

string countryName = person.Country.Name; 

...将达到数据库,调用的“名称”属性将加载整个客户实例。

这种行为假定您已经设置好你的映射像这样:

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

(注意,为lazy =“代理”是默认值)。

简而言之,不需要将域模型中的外键映射到NHibernate。