谈一下linq to sql的试图使用有关问题
谈一下linq to sql的试图使用问题
linq to sql可以通过交互式操作设计实体表,但是在使用视图时显得很不方便,比如建立了
实体表t1,列分别是t1_c1,t1_c2,t1_c3 和 实体表t2,列分别t2_c1,t2_c2,t2_c3,t2_c4
如果要使用两个表连接的视图,该怎么办?
如果返回的是t1表,wcf可以写出:
如果返回的是t2表,wcf可以这样写:
如果两个表的列都要返回,该怎么办,问题出在linq to sql中没有对应的两个表的实体
解决的办法是:在linq to sql中再定义一个实体,这里不妨把它称为视图实体 t1_t2_view,其列为t1_c2,t2_c4,此时wcf就可这样写了:
我想解决视图问题是否可以用上述思路,请诸位讨论评价。
------解决方案--------------------
我谈一下对 ADO.NET Entity Framework 的印象,仅是凭印象,不保证是对的,而且不知道在 LINQ to SQL 中是否有对应的相同效果。
1. 如果不是为了Silverlight,在 EF 中,对于实体的查询,包括多个实体的查询,
除了可以将各个实体的投影以匿名类的方式返回(即 var),还可以以 DbDataRecord 结果集的方式返回,
其数据结构和 DataTable 中的 DataRow 是类似的。
很可惜的是,采用这种方式的话,传递到Silverlight端需要进行转化,和使用DataTable一样。
2. 如果不是在 WCF 中使用,其实以匿名类的方式返回是最为简单的,在同一个应用程序中可以直接使用匿名类。但是更遗憾的是,匿名类由于没有启用[DataContract]、[DataMember],不可能通过WCF进行传输。
3. 要同时在 WCF 和 Silverlight 中使用,就只有采用创建自定义的启用[DataContract]的实体类了,
而且,这样的实体类并非要在 EF 或者 LINQ to SQL 的设计器设计。
事实上,我一直没搞明白,在EF的设计器中,新建的实体(或者是视图)由于在 Storage模型上不能和数据库
的表或视图对应,所以在EF设计器中总是会报大意为“Concept概念模型和Storage模型”的错误的,
但是不影响代码的编译和运行。 ---- 这点我忘了LINQ to SQL有没有相同的现象。
4. 我猜测在 EF 设计器、LINQ to SQL 设计器中可以手工创建新实体、视图的一个更大的用意是为了能对
数据库中的某些表或视图进行 INSERT、UPDATE、DELETE 等操作。
像海哥遇到的这种情况,由于并不涉及到INSERT、UPDATE、DELETE 等操作,所以手工创建实体或者在设计器中创建实体/视图都可以。
但是这样也带来一个值得考虑的问题,究竟应当创建多少个实体才合适?
举例之, 有 User 、 FormA、FormB、FormC 等4个表, User 表有 UserId 和 RealName(真实姓名),
FormA、FormB、FormC 这三个表都有 UserId 字段。
在不同的查询页面,如FormA查询页面,要求显示出 FormA 的 UserId 以及对应的 RealName,
在FormB查询页面,要求显示出 FormB 的 UserId 以及对应的 RealName ...
那么,该创建多少个视图?
方式一: 为每一种组合创建一个视图, 也就是说 FormA+User 为一个视图,FormB+User 为一个视图,FormC+User 为一个视图,
这似乎没有什么问题,可是问题大得很呢, 如果要同时查询 FormA 和 FormB 呢,那不是又得创建 FormA+User + FormB+User 的视图?
方式二: 根据具体的页面来创建 Model ,再根据 Model 来决定要在 WCF 中创建什么视图。
这是很难接受的一种设计方式,WCF端的实体定义竟然受制于Silverlight端,
但是,WCF RIA Services的推广,多多少少会促成这种设计方式。
方式三: 使用 IValueConverter。 这是我最推崇的方式,也就是不会创建任何 FormX + User 的视图,
而是在 Silverlight 端通过 IValueConverter ,将 UserId 转换为 RealName。
如果 User 表是基础数据,强烈推荐这么做。
方式四: 使用导航属性,而且是一对一的导航。
FormX 中除了有 UserId 属性外,还有一个 User类型的 导航属性,如名为 UserObject,
在查询时,通过 LoadWith() 等各种方式将对应的 User 也一起查询出来,然后返回至 Silverlight 端。
这种好处是方便了 Silverlight 端的使用,
坏处是 WCF 端变复杂了, 不仅是 LINQ 语句复杂了,而且很可能造成 SQL 的查询性能极其低下,
同时还要控制好延迟加载,避免因为 User类型 还有子导航属性而不能被序列化。
一下子写了这么多,额,睡觉去了,明天还要赶早班车,体验“被”高速。
linq to sql可以通过交互式操作设计实体表,但是在使用视图时显得很不方便,比如建立了
实体表t1,列分别是t1_c1,t1_c2,t1_c3 和 实体表t2,列分别t2_c1,t2_c2,t2_c3,t2_c4
如果要使用两个表连接的视图,该怎么办?
如果返回的是t1表,wcf可以写出:
- VB.NET code
<operationcontact>public function t1_t2_view as list(of t1) return (from s1 in dc.t1,s2 in dc.t2 where t1.t1_c1=t2.t2_c1 select s1).tolist end function
如果返回的是t2表,wcf可以这样写:
- VB.NET code
<operationcontact>public function t1_t2_view as list(of t2) return (from s1 in dc.t1,s2 in dc.t2 where t1.t1_c1=t2.t2_c1 select t2).tolist end function
如果两个表的列都要返回,该怎么办,问题出在linq to sql中没有对应的两个表的实体
- VB.NET code
<operationcontact>public function t1_t2_view as list(of ?) return (from s1 in dc.t1,s2 in dc.t2 where t1.t1_c1=t2.t2_c1 select t1.t1_c2 t2.t2_c4).tolist end function
解决的办法是:在linq to sql中再定义一个实体,这里不妨把它称为视图实体 t1_t2_view,其列为t1_c2,t2_c4,此时wcf就可这样写了:
- VB.NET code
<operationcontact>public function t1_t2_view as list(of t1_t2_view) return (from s1 in dc.t1,s2 in dc.t2 where t1.t1_c1=t2.t2_c1 select t1.t1_c2 t2.t2_c4).tolist end function
我想解决视图问题是否可以用上述思路,请诸位讨论评价。
------解决方案--------------------
我谈一下对 ADO.NET Entity Framework 的印象,仅是凭印象,不保证是对的,而且不知道在 LINQ to SQL 中是否有对应的相同效果。
1. 如果不是为了Silverlight,在 EF 中,对于实体的查询,包括多个实体的查询,
除了可以将各个实体的投影以匿名类的方式返回(即 var),还可以以 DbDataRecord 结果集的方式返回,
其数据结构和 DataTable 中的 DataRow 是类似的。
很可惜的是,采用这种方式的话,传递到Silverlight端需要进行转化,和使用DataTable一样。
2. 如果不是在 WCF 中使用,其实以匿名类的方式返回是最为简单的,在同一个应用程序中可以直接使用匿名类。但是更遗憾的是,匿名类由于没有启用[DataContract]、[DataMember],不可能通过WCF进行传输。
3. 要同时在 WCF 和 Silverlight 中使用,就只有采用创建自定义的启用[DataContract]的实体类了,
而且,这样的实体类并非要在 EF 或者 LINQ to SQL 的设计器设计。
事实上,我一直没搞明白,在EF的设计器中,新建的实体(或者是视图)由于在 Storage模型上不能和数据库
的表或视图对应,所以在EF设计器中总是会报大意为“Concept概念模型和Storage模型”的错误的,
但是不影响代码的编译和运行。 ---- 这点我忘了LINQ to SQL有没有相同的现象。
4. 我猜测在 EF 设计器、LINQ to SQL 设计器中可以手工创建新实体、视图的一个更大的用意是为了能对
数据库中的某些表或视图进行 INSERT、UPDATE、DELETE 等操作。
像海哥遇到的这种情况,由于并不涉及到INSERT、UPDATE、DELETE 等操作,所以手工创建实体或者在设计器中创建实体/视图都可以。
但是这样也带来一个值得考虑的问题,究竟应当创建多少个实体才合适?
举例之, 有 User 、 FormA、FormB、FormC 等4个表, User 表有 UserId 和 RealName(真实姓名),
FormA、FormB、FormC 这三个表都有 UserId 字段。
在不同的查询页面,如FormA查询页面,要求显示出 FormA 的 UserId 以及对应的 RealName,
在FormB查询页面,要求显示出 FormB 的 UserId 以及对应的 RealName ...
那么,该创建多少个视图?
方式一: 为每一种组合创建一个视图, 也就是说 FormA+User 为一个视图,FormB+User 为一个视图,FormC+User 为一个视图,
这似乎没有什么问题,可是问题大得很呢, 如果要同时查询 FormA 和 FormB 呢,那不是又得创建 FormA+User + FormB+User 的视图?
方式二: 根据具体的页面来创建 Model ,再根据 Model 来决定要在 WCF 中创建什么视图。
这是很难接受的一种设计方式,WCF端的实体定义竟然受制于Silverlight端,
但是,WCF RIA Services的推广,多多少少会促成这种设计方式。
方式三: 使用 IValueConverter。 这是我最推崇的方式,也就是不会创建任何 FormX + User 的视图,
而是在 Silverlight 端通过 IValueConverter ,将 UserId 转换为 RealName。
如果 User 表是基础数据,强烈推荐这么做。
方式四: 使用导航属性,而且是一对一的导航。
FormX 中除了有 UserId 属性外,还有一个 User类型的 导航属性,如名为 UserObject,
在查询时,通过 LoadWith() 等各种方式将对应的 User 也一起查询出来,然后返回至 Silverlight 端。
这种好处是方便了 Silverlight 端的使用,
坏处是 WCF 端变复杂了, 不仅是 LINQ 语句复杂了,而且很可能造成 SQL 的查询性能极其低下,
同时还要控制好延迟加载,避免因为 User类型 还有子导航属性而不能被序列化。
一下子写了这么多,额,睡觉去了,明天还要赶早班车,体验“被”高速。