徒劳的尝试 -- 动态修改LINQ TO SQL的表名称

  最近有点空闲时间,抽空看了一下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
 [System.Data.Linq.Mapping.DatabaseAttribute(Name="dnt_2")]
    
public partial class DntDataContext : System.Data.Linq.DataContext
    
{
      

                
public Query<Userinfo> Userinfos; //该Query继承自IQueryable


    
        
public DntDataContext(System.Data.IDbConnection connection) :
                
base(connection, mappingSource)
        
{
                    QueryProvider provider 
= new DbQueryProvider((DbConnection)connection);
                    
this.Userinfos = new Query<Userinfo>(provider);
            
        }

        
    }

       前端使用代码如下:
 

Code
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.ToArray())
                
{
                    Console.WriteLine(user.username);
                }


                Console.ReadLine();
            }

     当然数据库链接对象可以封装到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
 public static int Delete<TEntity>(this Table<TEntity> table, Expression<Func<TEntity, bool>> predicate)
            
where TEntity : class
        
{
            
string tableName = table.Context.Mapping.GetTable(typeof(TEntity)).TableName;
            
string command = String.Format("DELETE FROM {0}", tableName);

            ConditionBuilder conditionBuilder 
= new ConditionBuilder();
            conditionBuilder.Build(predicate.Body);

            
if (!String.IsNullOrEmpty(conditionBuilder.Condition))
            
{
                command 
+= " WHERE " + conditionBuilder.Condition;
            }


            
return table.Context.ExecuteCommand(command, conditionBuilder.Arguments);
        }

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


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

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

     源码:/Files/daizhj/linqkit.rar


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值