现在的位置: 首页 > 综合 > 正文

浅谈Linq to Sql 的不足

2012年06月04日 ⁄ 综合 ⁄ 共 2560字 ⁄ 字号 评论关闭
    前两星期,因为项目的需要,静下心来读完了《Pro.LINQ.Language.Integrated.Query.in.Csharp.2008》的 linq to object 和 linq to Sql 部分,希望能将Linq to Sql 应用在我们的项目中。读完后,颇有些心得,也深感到 Linq to Sql 的不足。

    这里我不讨论Linq的基本语法,也不讨论怎么用 Linq to Sql 来对数据库做SIUD操作,关于这方面的文章,网上已经有很多了。这里主要谈Linq to Sql的不足之处。

不足1:规则太死,可扩展性少
    这里说的规则太死,主要指业务层实体与数据库表的绑定。基本上只能是一个实体对象对应于一个表,而且,对实体对象的要求太多,比如,(1)该实体对象必须要有默认无参构造方法(如果没有也会编译通过,但无法运行,因为Linq to Sql是通过反射来构造对象,而且用的是该对象的无参构造方法);(2)该实体的所有实体存储字段都不能有readonly关键字(反射要对该字段写值);(3)如果该实体存在对子对象(“一对多”关系的“多”一方的实体对象)的一个列表,则该列表必须是EntitySet<T>类型;(4)如果该实体有对父对象(“一对多”关系的“一”一方的实体对象)的引用,则该应用类型必须是EntityRef<T>类型,而且还要有相对于父对象主键这样的字段存在。所有这些规则,注定了业务层实体对象基本没有办法自己来手写以进行自定义,进行扩展。那有人说了,本来就没让你手写,有SqlMetal和可视化设计工具存在,还手写,吃饱了撑着。我同意这些工具确实非常有用,但是这些工具生成的实体满足我们业务的需要吗?因为业务的变化是多样的,而过多的条条框框却大大缚束了我们的手脚。

不足2:不支持TimeSpan
    真是不可思议,实体类的TimeSpan字段怎么都没法直接映射到Sql Server的列中去(也许我没找对方法,若大家有办法,欢迎告知)。怎么办?难道要变通一下。是可以变通,而且变通的办法很多,但是,这种基本的类型都要变通才能实现,难道说这是一个足够成熟足够强大的框架所应该展现给大家看的吗?

不足3:透明性不够,使用上有困难
    我在看书之前,曾写过这样的代码,如下:
            using (ProgramConsoleDataContext db = new ProgramConsoleDataContext())
            {
                BaseTask baseTask = new BaseTask()
                {
                    Name = "jhh",
                };

                db.BaseTasks.Attach(baseTask);
                db.SubmitChanges();
            }
    结果运行失败,当然我现在知道为什么失败,但这也暴露了一个问题,就是使用者在使用Linq to Sql时,必须清楚DataContext对象的内部运作方式。看到Table<T>的“InsertOnSubmit”与“DeleteOnSubmit”这样的方法,就足以说明其封装性不够这样的问题。实际上,“InsertOnSubmit”原来设计的名字叫“Add”,“DeleteOnSubmit”原来的名字叫“Remove”,请问,你是喜欢后面的名字还是前面的名字,是喜欢后面的封装还是前面的封装?估计原来Linq to Sql设计团队的目标是提供一个封装性更强的框架,但后面因为种种原因没有实现,于是退而求其次,但怕大家误解“Add”与“Remove”这样方法,于是改成现在的名字,以强调“Submit”的概念(纯属个人猜测)。
    DataContext所提供的实体变更跟踪功能是一大亮点,但使用上感觉不是很方便,也许是我没找到好的运用模式。我在想,我是该永久保存该对象的一个引用呢,还是用到一次建一次对象。如果采用第一种方法,那么我的程序将随着运行时间的增长而Load越来越多的数据,最后,可能整个数据库都在Load进来;那如果采用第二种方法,那么我怎么利用它提供的实体变更跟踪功能呢?当然,可以使用Table<T>的Attach方法,但我不是每次都知道UpdateMode的方式,而且,要是我要Attach的这个对象是个大对象呢,下面挂了很多的EntitySet呢,我又该怎么Attach?我思考了很久,没有找到答案。

不足4:性能问题
    这个就不用说了,通过反射来实现的,当然有损失,也能接受,现在的ORM有不损失性能的吗?所以,这个可以说是问题,也可以说不是问题,大家都理解。但是,DataContext的实体变更跟踪的实现,却又是以性能、空间来换取的。不信你试试,在DataContext中Retrieve一个实体,然后更改该实体,你看看你的实体构造方法被调用了几次?是不是两次?为什么?因为Retrieve时一次,更改该实体时又一次,因为DataContext保存了该实体的原始副本。本来,我听说,在实体中实现INotifyPropertyChanging与INotifyPropertyChanged这两个接口后,DataContext就能根据该接口提供的功能来进行实体变更跟踪,我想,这样就不会创建一个副本了吧,结果发现还是建了一个副本,这是为什么?不知道。

    我还没有用Linq to Sql做过项目,因此以上的看法可能都不是很成熟。实际上,我想,Linq to Sql本来的定位就不是面向企业级运用的,我们也不要对它要求太多,实际上,简单就是它最大的美。我认为它适合于做一些比较简单的、业务逻辑不复杂的项目,但不适合做大的项目,我甚至认为中型的项目也不适合用它来做。目前Ado.net Entity Framework已经bate3了,期待它带来的Linq to entities能带给我们惊喜。

    最后,提出一个疑问:ORM真的有大的前景吗?大规模的项目有用ORM的吗?什么时候会有成熟的面向对象的数据库产品,或者因为关系模型在数学上的优美性而永远不会有呢?

抱歉!评论已关闭.