随笔-105  评论-2122  文章-18  trackbacks-49
  最近有点空闲时间,抽空看了一下LINQ方面的东西。好在园子里这方面的系列文章很多. 免去了不少查找
的时间. 因为本人习惯于学完就动手尝试,而我们的产品中也都将访问数据库的SQL语句统一封装进了DLL.
所以就想先拿产品练一下手:)

     但万事开头难,一用上才发现有一个不大不小的问题挡在了面前.就是使用LINQ TO SQL模板生成代码后,
会在相应的数据库实体类上绑定一个tablename属性.如下代码:


[Table(Name="dbo.dnt_users")]
    
public partial class Userinfo : INotifyPropertyChanging, INotifyPropertyChanged
    
{
 

      dnt_users是数据库中的物理表.而我们的产品有一个特性,就是允许用户定制表名称的前缀.其实"dnt_"
就是表的前缀名.而这个值(前缀)是通过产品中的Tableprefix属性获取的.Tableprefix属性返回的值是通过
dnt.config中配置的.

      所以这就要求在程序运行时动态加载表(前缀)名称.所在本人在网上开始四处找这方面的文章和资料.
但找到的并不是特别对症。因为才自己动手实验一下,看看有什么好方法:)

    尝试1:
    通过常量方式将表属性[Table(Name="dbo.dnt_users")]替换成:
            [Table(Name="dbo." + DntDataContext.tableprefix +"users")]

    而tabalprefix定义如下:
     public const string tableprefix = "dnt_";

[System.Data.Linq.Mapping.DatabaseAttribute(Name
="dnt_2")]
    
public partial class DntDataContext : System.Data.Linq.DataContext
{
    
    
public const string tableprefix = "dnt_";
    
}

     虽然这种方式将前台的名称抽取出来,将因为是采用常量方式,所以无法进行动态绑定.所以这次尝试是
失败的.


      尝试2: 替换DataContext生成的CommandText内容
      因为LINQ TO SQL最终还是被翻译成SQL,所以本人又使用下面的方法进行测试:
  
 DntDataContext ddc = new DntDataContext();
    var exp 
= from u in ddc.Userinfo
               orderby u.uid ascending
              select u
    
string query = ddc.GetCommand(exp).CommandText.Replace("dnt_""daizhj_");
    var result 
= ddc.ExecuteQuery<Userinfo>(query, 0);
    Console.WriteLine(((Userinfo[]) result.ToArray())[
0].username);

    上面代码段的ddc.GetCommand(exp).CommandText.Replace("dnt_", "daizhj_")是做的这个工作.
虽然这次采用替换方式解决了问题.但看了代码的朋友会发现,代码变得很丑,本人也是这么看的.即使封装
了也是很难受.没办法,放弃:(


     尝试3:   继承并实现IQuerable接口

     好在Matt Warren在他的文章中提到过如果建立一个IQueryable Provider(已修改, 更多内容参见这里).
另外LoveCherry也将这篇文章翻译了过来,大家有兴趣不妨看一下,很有意思,  详情点击这里:)

    所以本人就直接使用了他在文中所说的方式.将DNTDataContext做了修改如下:
 

Code

       前端使用代码如下:
 

Code

     当然数据库链接对象可以封装到DntDataContext中,让代码的整体感觉更LINQ一些.
相关的代码下载会在本文结尾处给出,详见LINQ.KIT代码中DbQueryProvider.cs文件.
(相关修改已通过注释给出).

     这次改动整体上能够满足查询上的需求,但是如果想使用相应的insert,update,delete
也能做到相应的表名替换的话,还是要从System.Data.Linq.Table入手.即让

using (SqlConnection con = new SqlConnection(global::Demo.Properties.Settings.Default.dnt_2ConnectionString))
            
{

                con.Open();

                DntDataContext ddc 
= new DntDataContext(con);

                IQueryable
<Userinfo> query = from u in ddc.Userinfos
                                        
where (u.uid > 1)
                                        select u;


                
foreach (Userinfo user in query)
                
{
                    Console.WriteLine(user.username);
                }


                Console.ReadLine();
            }


     返回的Userinfo类所绑定的表是被替换完成的表名称. 因为本人时间和精力有限,无法再去做进一步的研究了.
但老赵的这篇文章给了我一些启发.其中下面的代码段就是他用来扩展DELETE功能的方法

 

Code

     我想应该可以在这里完成相应的表名称的替换,实现起来也很容易.


      经过这一番折腾,我发现如果LINQ TO SQL 支持通过XML配置文件进行绑定才是最终的理想方案
因为本人又开始四处搜索这方面的信息,发现了这篇文章:)
  
     原来还真有,只是自己刚入门心急不知道,所以才兜了这么一大圈.看来以后还要认真耐心看文档和相应的方
法提示了, 好在这种低级错误也不是犯过一次两次了:)

     不过收获还是有的,如果大家有什么更好的方法和意见,欢迎在回复中进行交流.

     源码:/Files/daizhj/linqkit.rar


posted on 2008-05-12 11:10 代震军 阅读(1384) 评论(17)  编辑 收藏 所属分类: LINQ

评论:
#1楼  2008-05-12 11:18 | Gray Zhang      
一直都用XML配置,这样DLINQ就对自己的实体没有侵入性,将来转ADO.NET或者EF都很方便
如果DLINQ真的完美,就不会考虑用XML配置了,只可惜DLINQ的问题多多啊

不过似乎DataContext里有个Meta什么的,不知道对动态修改有没有用...
  回复  引用  查看    
#2楼  2008-05-12 11:21 | Gray Zhang      
嗯,试了一下
ctx.Mapping.GetTable(typeof(BlogEntry)).TableName
这样确实可以取得表名,但是...TableName是只读的..
  回复  引用  查看    
#3楼  2008-05-12 11:37 | SZW      
在XML里面设置还有一个好处就是,当ORM改变的时候,即使VS自动重构.designer.cs,也不怕以前的修改丢失,不然每次更新之后都要重复劳动了。
  回复  引用  查看    
#4楼  2008-05-12 11:45 | Jeffrey Zhao      
@Gray Zhang
“一直都用XML配置,这样DLINQ就对自己的实体没有侵入性”不觉得会造成或者不造成所谓的“侵入性”。就算用XML Mapping还不是使用了EntityRef,EntitySet等类型吗?无论是Attribute还是XML其实都是一样的。
  回复  引用  查看    
#5楼  2008-05-12 11:48 | Jeffrey Zhao      
@SZW
大部分情况里是不需要修改自动生成的文件的吧,要修改都用Partial Class。
  回复  引用  查看    
#6楼 [楼主] 2008-05-12 12:54 | 代震军      
@SZW
您所说的修改丢失是不是类似于在ASPX上的控件绑定事件在切换到aspx.cs中时可能丢失的问题吗?
  回复  引用  查看    
#7楼 [楼主] 2008-05-12 13:27 | 代震军      
@Jeffrey Zhao
老赵,您好.
我目前有个问题,限于手工上的资料不多.就是EntityRef,EntitySet这样的东东通过XML或属性绑定的情况下,那种效率(运行速度会更高一些)?
  当然我觉得可能是属性绑定高.但XML的灵活性很大,可以让程序员或用户(本人更推荐是程序员)来进行绑定.就像Hibernate里面一样.

  当然最好还要有参数绑定(如构造函数初始化参数的设置)都在XML中可以设置.而目前我手头上的ADO ENTITY FRAME SAMPLE中的csdl还没有这方面的东西.可能是我刚上手,还没摸到门道.但如果没有的话,我想这可能会是一种遗憾:)

  

  回复  引用  查看    
#8楼 [楼主] 2008-05-12 13:32 | 代震军      
@Gray Zhang
其实在EF中可以通过msl来进行绑定,如下:
<EntitySetMapping Name="Orders">
<EntityTypeMapping TypeName="IsTypeOf(NorthwindModel.Order)">
<MappingFragment StoreEntitySet="Orders">

第一行应该就是实体类的名称.而第三行就是数据库中的表关联的名称.(从字面上看是这层意思:)
  回复  引用  查看    
#9楼  2008-05-12 14:29 | Jeffrey Zhao      
@代震军
MappingSource是个抽象类,理论上都可以自己实现的,呵呵。
  回复  引用  查看    
#10楼  2008-05-12 14:52 | Gray Zhang      
@Jeffrey Zhao
是这样的,我也不喜欢在实体类中加入EntityRef和EntitySet,这要讨论下去会变成失血贫血模式的讨论,我个人还是喜欢保证实体类的纯净,而不是变成"只属于DLINQ的Entity"
  回复  引用  查看    
#11楼 [楼主] 2008-05-12 14:54 | 代震军      
@Jeffrey Zhao
这个我也是考虑过,像XmlMappingSource,AttributeMappingSource就是这样的东东.但像这种情况如果自己搞倒不如微软在EF或相关产品中直接支持来的方便,况且我担心的是如果自己辛苦搞出来了之后,下一个版本它又变了,我说的不是方法更名这么简单:) ,那就要受制于它:(
  回复  引用  查看    
#12楼  2008-05-12 21:18 | Gray Zhang      
@代震军
斗胆回复一下...我觉得用Attribute还是Xml来配置在效率上没有影响,因为DLINQ在读取配置后应该会在内存中生成一个副本,以后都是在内存中操作了
  回复  引用  查看    
#13楼  2008-05-12 21:31 | Jeffrey Zhao      
@Gray Zhang
不了解怎么变成贫血失血的讨论了,呵呵。你现在用了EntityRef和EntitySet难道不是“只属于DLINQ的Entity”?
  回复  引用  查看    
#14楼  2008-05-12 21:32 | Jeffrey Zhao      
@代震军
你想搞个通用的还是满足项目需要的?其实不要担心那么多,技术没那么容易落伍的……
  回复  引用  查看    
#15楼 [楼主] 2008-05-13 09:04 | 代震军      
@Jeffrey Zhao
我目前是想做一个项目能用的,当然可设置的功能多一些会更好(就像上面说的),不过也考虑过如果功能代码稳定后移植到其它项目中,不过前提是LINQ本身要先"稳定"下来,有一些的成功(商业)应用案例之后:)
  回复  引用  查看    
#16楼 [楼主] 2008-05-13 09:09 | 代震军      
@Gray Zhang
这一块我个人感觉还是有测试用例证实一下最好.就像是linq to sql 与 ado.net访问速度效率测试一样:)
  回复  引用  查看    
#17楼 [楼主] 2008-05-13 09:25 | 代震军      
@Jeffrey Zhao
其实LINQ本身在我看来是一种纯数据(不含方法操作,即哑数据)的东西.从微软给的一些例子(官方的SAMPLE)可以看出是这个层面上的设计方案(当然我个人猜测可能出于分布式设计等因素的考虑).
而EntityRef和EntitySet这种关系引入到linq中一直是我所希望的,因为以前做的项目中就有这样的设计.在hibernate中也有many-to-one, one-to-many, many-to-many这样的设置以便通过XML在表之间建立关系.这一点无可厚非.
而域模型之类的东东我想这里就不必谈了,因为不同的人对不同的模型喜爱程度和应用背景都不同.且不用的模型(充血,失血,胀血,贫血)的应用环境也有很大差异.必定到今天还没争出个所以然(特别是贫血和充血),我个人也有些累了,但我会关注这方面的资料:) 
同时感谢您的回复.
如果可以的话,我想把您的MSN或QQ加进来,以便有什么问题及时讨论,呵呵:)

我的MSN是: daizhj4@hotmail.com
qq:360709855
  回复  引用  查看    

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-05-19 15:23 编辑过
 
另存  打印