分享高效的实体类操作类,分析其优势,可自己写替代EF的ORM框架

qldsrx 2012-04-12 10:43:05
加精
这次发博发这里了,免积分下载,支持获取动态实体类并让控件加载。
http://blog.csdn.net/qldsrx/article/details/7452346

下面是代码分析:

public class Dog
{
public int? Age { get; set; }
public Guid Id { get; set; }
public string Name { get; set; }
public float? Weight { get; set; }

public int IgnoredProperty { get { return 1; } }
}

var guid = Guid.NewGuid();
var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid });

这个查询,返回的是Dog类的集合,参数是一个匿名类,2个属性(Age和Id),其实除了匿名属性作为参数,实体类本身也可以作为参数,这意味着你可以很方便得从一个实体作为条件,获取其相关联的其它实体,写代码会很方便,无需自己写参数构造过程了。

在看这段代码:

connection.Execute(@"insert MyTable(colA, colB) values (@a, @b)",
new[] { new { a=1, b=1 }, new { a=2, b=2 }, new { a=3, b=3 } }
).IsEqualTo(3); // 3 rows inserted: "1,1", "2,2" and "3,3"

这是非常有意义的写法,当我们批量更新一个List<T>内的实体的修改是,直接把这个List作为参数传递给它即可,Sql语句自己定义。而以前的写法都是循环集合中的每个实体,然后创建参数,对数据库提交修改。

最后看这段代码:

class User
{
public int Id { get; set; }
public string Name { get; set; }
}
class Post
{
public int Id { get; set; }
public User Owner { get; set; }
public string Content { get; set; }
public Comment Comment { get; set; }
}
public void TestMultiMap()
{
var createSql = @"
create table #Users (Id int, Name varchar(20))
create table #Posts (Id int, OwnerId int, Content varchar(20))

insert #Users values(99, 'Sam')
insert #Users values(2, 'I am')

insert #Posts values(1, 99, 'Sams Post1')
insert #Posts values(2, 99, 'Sams Post2')
insert #Posts values(3, null, 'no ones post')
";
connection.Execute(createSql);

var sql =
@"select * from #Posts p
left join #Users u on u.Id = p.OwnerId
Order by p.Id";

var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post; }).ToList();
var p = data.First();

p.Content.IsEqualTo("Sams Post1");
p.Id.IsEqualTo(1);
p.Owner.Name.IsEqualTo("Sam");
p.Owner.Id.IsEqualTo(99);

data[2].Owner.IsNull();

connection.Execute("drop table #Users drop table #Posts");
}

这是多实体联合查询的示例,通过传递一个关系函数,得到一个根实体,访问根实体Post的属性User,可以得到相关联的User,这在多表联合查询中修改中非常有意义,而这个根实体其实可以用动态实体来替代,这样就非常完美了。

有了上面这些强大的基础功能,我们只要封装下从数据库中映射的实体类的基本SELECT、INSERT、UPDATE、DELETE语句,那么连SQL语句部分都可以不用写了,一个非常强大的ORM框架就此诞生,还支持动态类型查询。

这个强大的实体类只能在直接访问数据库的情况下使用,如果要在远程方法中调用(如WCF),则必须做大的改动,而Silverlight对匿名实体类的处理又有所不同,因为不支持TypeDescriptor类,将无法动态构造属性说明,因此必须动态创建一个新的类型来处理,这个处理难度非常大,目前正在设计阶段,主要技术问题都已解决,正在ORM框架的构建中。

本人业余编程,自认为水平已经很专业了(仅限C#),如果有C++高手可以指点下C++下面的实体类处理,我好让设计的动态实体类可以更多的跨语言,跨平台。
...全文
10744 363 打赏 收藏 转发到动态 举报
写回复
用AI写文章
363 条回复
切换为时间正序
请发表友善的回复…
发表回复
ydtpan 2012-04-28
  • 打赏
  • 举报
回复
与期争论不休,没有结果。 不如楼主给大家讲讲这个类的优点在哪儿。
让大家有收获,比争论是直接面向数据库编程或是面向对象编程哪种方式好,来得有价值。
谈谈这个类你觉得好的,抽几个出来详细说明。
owen_chen007 2012-04-27
  • 打赏
  • 举报
回复
活到老学到老
窗户纸 2012-04-25
  • 打赏
  • 举报
回复
当然我觉得你的模式也有缺陷,就是“类SQL" 语句仍然需要学习才能掌握,新上手的人对SQL都有恐惧感,就甭提你的“类SQL”了。
窗户纸 2012-04-25
  • 打赏
  • 举报
回复
从我上面举的几个小例子看,业内已有的“框架”类通用软件(如LING to Sql, Hibernate)之类的在实现特殊功能和特殊效率提升存在局限性,而自己定制的系统可以很容易的实现我所需要的后期灵活优化。

在发散一下,这里面有些提到实体与数据表关系时表述的很混乱,比如一个实体管理多少表之类的,实际上对象体系与数据表体系是有联系的,做过一两个系统,真正按照面向对象的设计思路做做 很容易就会发现。

不过很多人抱怨的面向对象编程问题,一个很重要的因素可以说是他抽象分析能力有待提高(比如用友号称有上千个表,但他每年结算就用一套新表,那数据表不多才怪,难道不能设计一个年份表去关联相关表解决吗?SAP不是这个设计,所以他没有上万张表,不然SAP架构设计师自己就自裁了,而用友则脸皮比较厚)
窗户纸 2012-04-25
  • 打赏
  • 举报
回复
[Quote=引用 358 楼 的回复:]
只有ycg_893、sp1234理解了我分享的操作类,其他人不是没发表见解,就是直接跑题谈论其它的去了。那么好的一个工具类不好好研究,而去纠结什么设计模式,真是本末倒置了。本想那么难的代码,看不懂你们可以多提问,我来解答细节,可惜却偏偏争论其它的去了。
[/Quote]
青龙老弟不要气馁,我粗看了一下代码,貌似你试图解决的是如何提高传统映射方式的处理效率问题。
比如对于传统的ORM模式如果查询年龄>2岁的黄色狗需要取所有狗逐一遍历结果,再提出合适对象返回集合,而你的方式直接使用特定的“类SQL"语句即可实现快速查询,其效率显然比单纯的ORM快很多,更新等也是类似。

我的项目所采用的方法是先不考虑效率,业务层及界面层编程人员仅对对象操作,在后期功能定型后再进行一个优化阶段,针对影响效率的数据提取方式设计并实现单独的接口及sql实现。

你的模式优点在一开始就可以保证系统的运行效率,但如果希望数据表变化后业务层不受影响,就需要对"类SQL语句"进行翻译。如数据库表的AGE 改成godAge, 业务层仍可使用Age属性。不知是否有实现。

另一种需求,比如用户在线标记属性,ORM写入会整个对象操作,而在线与否由数据库控制,必须单独写入及读取,这就必须建立一个特定的接口进行操作,否则就会造成错误(客户端改了用户信息,结果用户下线变成上线了)。
另外有人提到表间级联查询时的效率问题,这个问题也很重要,我们的处理方法是后期设置专门的接口,定制sql实现,
比如:查询存在年龄〉2岁的黄色的狗的狗舍集合,我们在狗舍对象中增加内部静态finddogzone(int age, short color)方法,
实现时select dogzone.* from dogZone inner join Dog on dog.dogzoneID=dogzong.id where
dog.age='{0}' and dog.color='{1}' ...
然后在顶级系统对象中增加开放的finddogzone(age,color)方法。
qldsrx 2012-04-25
  • 打赏
  • 举报
回复
只有ycg_893、sp1234理解了我分享的操作类,其他人不是没发表见解,就是直接跑题谈论其它的去了。那么好的一个工具类不好好研究,而去纠结什么设计模式,真是本末倒置了。本想那么难的代码,看不懂你们可以多提问,我来解答细节,可惜却偏偏争论其它的去了。
showjim 2012-04-23
  • 打赏
  • 举报
回复
[Quote=引用 333 楼 的回复:]
2.ORM的根本缺陷就是认为业务和数据的映射关系,你们所说的所谓"实体"无异于把数据库硬拷贝一遍,
无论是DBFirst还是CodeFirst,根本思想还是"数据驱动",用一种实现驱动另一种实现
并且,除非你们能从代码中自动"反射"出完整的设计文档,
否则,项目很难快速重建
[/Quote]
ORM映射与业务没有必然的直接关系,你说的缺陷不成立。
数据库硬拷贝确实能带来一些优势,并不是茫无目的。
CodeFirst不仅仅是数据访问,所以它并不是你眼中的"数据驱动"。CodeFirst是基于程序定义驱动的自动化,也许是数据结构,也许是函数定义,也许是一个模版,也许...我个人的实现多数针对.net元数据。
程序就是设计文档,要"反射"出所谓的“文档”是很简单的事。
因为IDE支持重构,项目的重建也很简单。
[Quote=引用 337 楼 的回复:]
你所赞成的那种基于ORM思想的所谓"实体"无法实现你所倡导的价值取向,
超过80%的这样的代码背后的业务逻辑都是在一遍遍重复实现,
(当然,我假设业务领域是基于数据库的企业信息管理系统)

设计师的工作不是编程也不是sql,他们的工作成果是设计文档,
项目的关键价值在设计文档,而不是那些代码,
一切软件生产工序都是有设计文档驱动的,
文档完整,就可以保证向后兼容和快速重建
[/Quote]
业务逻辑是否重复实现与ORM毫无关系。
我不明白,Code First不能向后兼容?不能快速重建?
[Quote=引用 338 楼 的回复:]
比如说,你实现一个订单业务,不应该依赖具体的数据结构,
哪怕设计的就是采购订单业务这样具体的业务,
那也不应该可数据库中的PurchaseOrder有任何依赖关系
这个业务实现应该支持的是:
任何实现了相同设计接口的数据结构和数据处理
[/Quote]
既然业务实现应该支持接口,这和ORM冲突吗?
ORM映射的仅仅是原始数据结构,可以仅相当于一个面向程序的扩展数据库操作接口。
zhongchengli 2012-04-21
  • 打赏
  • 举报
回复
[Quote=引用 328 楼 的回复:]

如果能封装SQL语句就更好了!
这样才能对应多种数据库!

参考--------------------------------
http://www.cnblogs.com/szp1118/archive/2011/03/30/ORM.html
设计思路:

1.数据库中的一张表需要和实体类进行对应,表中的字段对应到实体类的属性,不一定都要一一对应,可以有属性不对应到表中,但是……
[/Quote]
还有就是我们的项目为了保护客户数据,数据库字段都是A,B,C...
zhongchengli 2012-04-21
  • 打赏
  • 举报
回复
如果能封装SQL语句就更好了!
这样才能对应多种数据库!

参考--------------------------------
http://www.cnblogs.com/szp1118/archive/2011/03/30/ORM.html
设计思路:

1.数据库中的一张表需要和实体类进行对应,表中的字段对应到实体类的属性,不一定都要一一对应,可以有属性不对应到表中,但是一般情况下数据库字段都应该对应到某个属性,否则就没法对该字段进行操作了。有时候在列表页和详细页需要获取的数据不同(列表页是少数几个字段),这种情况下可以定义一个少量字段的实体类,再定义一个所有字段的实体类(继承至前一个类)。

2.由于.net的基本类型例如int,bool等都是值类型,意味着无法赋值为null,它们都有默认初始值,int为0,bool为false,这样的话自动处理就无法分辨出是默认赋值还是用户自己赋值,所以实体类中的属性就必须是引用类型,对于.net基本类型就要做可空处理了(.net 2.0新增功能),如 int? , bool? 这样来定义实体类的属性类型。
--------------------------------------------

哪位高手给个好点的设计思路?

  • 打赏
  • 举报
回复
点开楼主一开头的连接,看到原文,那么就可以看到lz他自己写的“为什么要开发此框架”的基本解释。理解楼主为什么要“自己开发框架”?理解楼主为什么首先要参考别人的框架?理解楼主为什么以使用中的“性能”为这个框架设计指标?

例如我们编程当然要追求最少量地设计对象类,但是不是说我们因此就绩效面向对象设计,不会面向对象设计的人跟滥用对象、继承概念的人其实是一样的。

因此去开发一个框架是有其原因的、有其目的,不是要求别人一定去模仿。不会按照自己的需要开发框架,跟做出几个无用反而降低生产率的框架,结果都是是一样的。
  • 打赏
  • 举报
回复
[Quote=引用 348 楼 的回复:]
那你发几个上来瞧瞧,
[/Quote]

晕!

我想你先尽量看懂楼主的帖子吧。
  • 打赏
  • 举报
回复
有一些框架总是正确的,关键是什么样的框架。

如果什么框架都没有,那么就是无头苍蝇式的开发,表面好像挺敏捷、而实际上只是一遍遍重复低层次的OA表单复制的“开发”工作。楼主的帖子,并不是在这个层面上才想到的,楼主也提示了,他是因为大量外部原因的影响、价值自己的水平足以开发一些工具类的项目(而不是只会编写OA表单),这才想到了要对传统的数据库表编程方法做出改变。
vsfdsfsd 2012-04-21
  • 打赏
  • 举报
回复
看是不是真的象你说的那么伟大,
vsfdsfsd 2012-04-21
  • 打赏
  • 举报
回复
[Quote=引用 346 楼 的回复:]
只有有人一个劲问“如何做?” --> 至于有人一个劲问“如何做?”


实际上所谓的“说概念条条是道,碰到实际问题束守无策”,这是对已经流行了超过15年的ORM毫无概念的表现。在ORM上流行的理论和书籍也很多,而且总是跟著名OOAD专著(而不是网路上的杂文)放在一起,作为“如何使用OOPL来实现ORM框架系统”的篇章。

我在各种项目中写过的ORM有好几个,还真的无法跟所谓“束手无策”这……
[/Quote]

那你发几个上来瞧瞧,
vsfdsfsd 2012-04-21
  • 打赏
  • 举报
回复
以用户需求为中心,然后什么对象,sql,
什么好用就用什么,对象sql,各有擅长,不要因为对象就去否定sql,
又不是搞传销,
  • 打赏
  • 举报
回复
只有有人一个劲问“如何做?” --> 至于有人一个劲问“如何做?”


实际上所谓的“说概念条条是道,碰到实际问题束守无策”,这是对已经流行了超过15年的ORM毫无概念的表现。在ORM上流行的理论和书籍也很多,而且总是跟著名OOAD专著(而不是网路上的杂文)放在一起,作为“如何使用OOPL来实现ORM框架系统”的篇章。

我在各种项目中写过的ORM有好几个,还真的无法跟所谓“束手无策”这样的描述扯上关系。
vsfdsfsd 2012-04-21
  • 打赏
  • 举报
回复
无招胜有招,
一切以用户需求为中心,而不是以什么对象啊,模式啊为中心,
以这些为中心,无疑是拿个套子把自己套住,
vsfdsfsd 2012-04-21
  • 打赏
  • 举报
回复
我们以前的会计老师,
说市面上的会计软件,没一个好用的,
都是程序员按自己的模式开发出软件,
然后要那些专业会计师,去适应程序员的模式,
用多了人都变傻了,

是鞋去适应脚,不是脚去适应鞋。
  • 打赏
  • 举报
回复
[Quote=引用 333 楼 的回复:]

引用 330 楼 的回复:
你宁可单独去“维护1000个数据库表”,然后再写1000中莫名其妙的DataTable组合(无模式)么?

写程序时,需要什么实体,就直接写什么业务,而数据库表自动化地维护(根本不需要更多人工操作),
1.设计文档自动更新数据库(DBMS不也是这样做的么?),并且只有涉及到新的没有实现过的业务逻辑的时候,才会需要人工编写代码;
2.ORM的根本缺陷就是认为……
[/Quote]

我所面对是,不是有没有数据结构的问题,而是像某些培训机构最喜欢的培训方式那样、只会拿着sql语句当设计的程序设计师,这时的问题就很严重了。

目前我只愿意围绕楼主的帖子,描述一下它可以做什么、如何做到的问题。只有有人一个劲问“如何做?”,请去问楼主。我对楼主的回复是有效的,楼主知道如何轻快地使用Attribute、DDL语句等来解决问题,这就足够了。别人有问题请去问楼主。
wanghui0380 2012-04-21
  • 打赏
  • 举报
回复
所以我们前面才会和你提IQueryable<T>,也就是不管以后怎么去提供那个privode,起码目前我并不关心,我们目前关心的是系统对象结构,边界提供,系统服务。
对于查询我个人是这么说,他总归是有手段解决的,他目前暂时不在我考虑范围内


也许后续提供有性能问题,他不重要,性能问题我们可以优化。第一步是把棋下赢,至于这棋是不是最好滴,我们说赢棋第一,先赢了才有话语权。

ps:有关上面那位纠缠Mvvm的和具体细节的兄弟,我先说一句不是我们和你说抽象,而是我们不能和你说具象的东西,一是微软本身依赖抽象,他依赖一些InontifyPropeytychanged,IErrrorInfo这些抽象,如果是我如果有人怎么说,我不会具体在问,我会先搞清楚这些接口都是啥,如何在具体项目里应用,只要你弄清楚他们,剩下的事情我们不用解释你就知道,同时对于lz也是一样,lz应该先去看一下IQueryable<T>,然后我们不用解释lz也就知道,他现在的东西微软不是没有,抛开linq2sql,抛开EF,如果我说我自己,可以如此

xxxx.join(yyyyy,y=>y.id,x=>x.id,(x,y)=>new (x=x,y=y)).where(p=>x.xx==1&y.yy==2)
我能提供正确的sql解析,并能正确查询出结果,那么lz就该理解我们的意思了
加载更多回复(308)

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧