当前位置:  开发笔记 > 编程语言 > 正文

为什么ORM被认为是好的但"选择*"被认为是坏的?

如何解决《为什么ORM被认为是好的但"选择*"被认为是坏的?》经验,为你挑选了3个好方法。

ORM通常不会涉及像select*这样的事情吗?

如果我有一个表,MyThing,包括A,B,C,D等列,那么通常会有一个对象,MyThing具有属性A,B,C,D.

如果该对象被看起来像这样的select语句不完全实例化,只获取A,B,而不是C,D,那将是邪恶的:

选择A,B来自MyThing/*不要得到C和D,因为我们不需要它们*/

但总是这样做也是邪恶的:

选择A,B,C,D/*获取所有列,以便我们可以完全实例化MyThing对象*/

ORM是否假设数据库访问速度如此之快,您现在不必担心它,因此您始终可以获取所有列?

或者,您是否有不同的MyThing对象,每个可能碰巧在select语句中的列组合对应一个?

编辑:在回答这个问题之前,请阅读Nicholas Piasecki和Bill Karwin的答案.我想我的问题很糟糕,因为许多人误解了它,但尼古拉斯100%理解它.和他一样,我对其他答案感兴趣.


编辑#2:与此问题相关的链接:

为什么我们需要实体对象?

http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx,特别是"部分对象问题和加载时间悖论"一节

http://groups.google.com/group/comp.object/browse_thread/thread/853fca22ded31c00/99f41d57f195f48b?

http://www.martinfowler.com/bliki/AnemicDomainModel.html

http://database-programmer.blogspot.com/2008/06/why-i-do-not-use-orm.html



1> Nicholas Pia..:

在我有限的经验中,事情正如你所描述的那样 - 这是一个混乱的情况,而且通常的应付"依赖"答案适用.

一个很好的例子是我工作的在线商店.它有一个Brand对象,在网站的主页上,商店销售的所有品牌都列在左侧.要显示此品牌菜单,所有站点需求都是整数BrandId和字符串BrandName.但是该Brand对象包含了大量其他属性,最明显的Description是可以包含大量关于文本的文本的属性Brand.关于它的两种方式,加载关于品牌的所有额外信息只是为了在无序列表中吐出它的名称是(1)可测量且显着慢,通常是因为大文本字段和(2)当它到来时非常低效记忆用法,建立大字符串,甚至在扔掉之前都不看它们.

许多ORM提供的一个选项是延迟加载属性.所以我们可以将一个Brand对象返回给我们,但是Description在我们尝试调用它的get访问器之前,这个耗费时间和内存浪费的字段是不可能的.此时,代理对象将拦截我们的调用并及时从数据库中删除描述.这有时候足够好,但已经烧了我足够多次,我个人不推荐它:

很容易忘记该属性是延迟加载的,只是通过编写foreach循环引入SELECT N + 1问题.谁知道当LINQ参与时会发生什么.

如果即时数据库调用失败,因为传输被弄糟或网络中断了怎么办?我几乎可以保证任何代码都是无关紧要的,因为string desc = brand.Description我没有期待那个简单的调用抛出一个DataAccessException.现在你刚刚以令人讨厌和意想不到的方式坠毁.(是的,我看到我的应用程序因此而努力下去.学到了很多东西!)

所以我最终做的是在需要性能或容易出现数据库死锁的场景中,我创建了一个单独的界面,网站或任何其他程序可以调用该界面来访问已查询的特定数据块计划仔细审查.该架构最终看起来像这样(原谅ASCII艺术):

Web Site:         Controller Classes
                     |
                     |---------------------------------+
                     |                                 |
App Server:       IDocumentService               IOrderService, IInventoryService, etc
                  (Arrays, DataSets)             (Regular OO objects, like Brand)
                     |                                 |
                     |                                 |
                     |                                 |
Data Layer:       (Raw ADO.NET returning arrays, ("Full cream" ORM like NHibernate)
                   DataSets, simple classes)

我曾经认为这是作弊,颠覆了OO对象模型.但从实际意义上讲,只要你使用这个显示数据的快捷方式,我认为它没问题.更新/插入以及您仍然通过完全水合,填充ORM的域模型,并且这种情况发生的频率(在我的大多数情况下)比显示特定的数据子集要少得多.像NHibernate这样的ORM可以让你做预测,但到那时我只是看不到ORM的意义.无论如何,这可能是一个存储过程,编写ADO.NET需要两秒钟.

这只是我的两分钱.我期待着阅读其他一些回复.



2> Bill Karwin..:

人们使用ORM来提高开发效率,而不是运行时性能优化.这取决于项目是否最重要的是最大化开发效率或运行时效率.

在实践中,可以使用ORM实现最高生产率,然后在完成后对应用程序进行概要分析以识别瓶颈.将ORM代码替换为自定义SQL查询,只有在您获得最大收益的情况下.

SELECT *如果您通常需要表中的所有列,那也不错.我们无法概括通配符总是好的或总是坏的.

编辑: Re:doofledorfer的评论......就个人而言,我总是在查询中明确命名列; 我从不在生产代码中使用通配符(尽管我在进行即席查询时使用它).最初的问题是关于ORM - 实际上,ORM框架SELECT *统一发布,填充相应对象模型中的所有字段并不罕见.

执行SELECT *查询可能不一定表明您需要所有这些列,并不一定意味着您忽略了您的代码.可能是ORM框架正在生成SQL查询,以确保您需要时可以使用所有字段.



3> Bryan Watts..:

Linq to Sql或IQueryable的任何实现都使用一种语法,最终使您可以控制所选数据.查询的定义也是其结果集的定义.

select *通过从ORM中删除数据形状职责,这可以巧妙地避免这个问题.

例如,要选择所有列:

from c in data.Customers
select c

要选择子集:

from c in data.Customers
select new
{
  c.FirstName,
  c.LastName,
  c.Email
}

要选择组合:

from c in data.Customers
join o in data.Orders on c.CustomerId equals o.CustomerId
select new
{
  Name = c.FirstName + " " + c.LastName,
  Email = c.Email,
  Date = o.DateSubmitted
}

推荐阅读
有风吹过best
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有