集成 linq to sql 和spring.net

最近一段时间,精力都放在将linq to sql 引入项目中的工作,由于框架所采用的ioc是spring.net , 将linq to sql 和spring.net集成也是自然的事情.可以预测的是,将来spring.net 官方必然会做这个事情. 所以,我目前的计划也只是满足自身所需的功能即可. 同时,此文也只是提供一种方法,细节请大家多多斟酌.

对于linq to sql 而言,同spring.net 集成的最大好处是事务机制, 你可以获得spring.net 灵活多变的事务支持,并提供你的非linq to sql 数据访问和linq to sql 运行在同一事务下的可能. 由于DataContext 由于你使用IDbConnection作为创建DataContext的参数,因此,不需要写很多代码就能和spring.data 的ado.net  事务支持集成.

集成主要包括以下部分
1. IDataContextFactory和其缺省实现DataContextFactory
2. LocalDataContextFactoryObject  ,其实如果原有的工厂类能符合ioc配置的需要,就没有必要为之提供对象的FactoryObject, 因为FactoryObject 通常需要重复一些配置属性,FactoryObject通常用于无法使用ioc配置的工厂类,通常,它也提供额外的配置检查功能. 我这个实现代码quick and dirty 建议大家不要学:)
3. DataContextTemplate

btw: 本来我不打算实现单独的DataContextFactory,但后来发现,为了符合spring.net 惯用法,这还是有必要的,现在的代码同上午略有不同

例子
TransactionTemplate tt  =  (TransactionTemplate)context.GetObject( " transactionTemplate " );

      tt.Execute(
delegate (ITransactionStatus status) {
        template.Execute(
delegate(DataContext db)
        
{
         
          Currency c 
= new Currency();
          c.Id 
= "t";
          c.Name 
= "t";
          c.ExchangeRate 
= 1;

          db.GetTable
<Currency>().Add(c);

          db.SubmitChanges();

          
return null;
        }
);
   

        template.Execute(
delegate(DataContext db)
        
{

          Currency c 
= db.GetTable<Currency>().FirstOrDefault(item => item.Id == "t");

          db.GetTable
<Currency>().Remove(c);

          db.SubmitChanges();

          
return null;
        }
);

        
return null;
      }
);

可以在插入后加一行 throw new Exception(); 来看看数据是否已经插入到数据库来检查工作是否正常.

声明
    < objects  default-lazy-init ="true"  xmlns ="http://www.springframework.net"  xmlns:database ="http://www.springframework.net/database" >
      
< database:provider  id ="dbProvider"  provider ="SqlServer-2.0"  connectionString ="server=(local);user id=sa;pwd=;database=xxx" />
      
< object  id ="dataContextFactory"  type ="SohoWorks.BusinessFramework.Data.Linq.LocalDataContextFactoryObject,SohoWorks.BusinessFramework" >
        
< property  name ="DbProvider"  ref ="dbProvider" />
        
< property  name ="DataContextType"  value ="xxxx,xxx" />
      
</ object >
      
< object  id ="dataContextTemplate"  type ="SohoWorks.BusinessFramework.Data.Linq.DataContextTemplate,SohoWorks.BusinessFramework" >
        
< property  name ="DataContextFactory"  ref  ="dataContextFactory" ></ property >
      
</ object >

      
< object  id ="transactionManager"  type ="Spring.Data.Core.AdoPlatformTransactionManager,Spring.Data" >
        
< property  name ="DbProvider"  ref ="dbProvider" />
      
</ object >
      
< object  id ="transactionTemplate"  type ="Spring.Transaction.Support.TransactionTemplate,Spring.Data" >
        
< property  name ="PlatformTransactionManager"  ref ="transactionManager" />
      
</ object >
    
</ objects >

DataContextFactory 是IDataContextFactory的默认实现, 它主要功能就是从一个DataContextType声明实例化DataContext,它只关心使用IDbConnection参数的那两个构造函数, DataContextFactory还可以提供额外的属性声明,像这个例子中的DefaultObjectTrackingEnabled之类的,以便你在实例化时进行相应的初始化.

最最关键的代码可能就是ConnectionUtils.GetConnectionTxPair了
IDataContextFactory
  public   interface  IDataContextFactory
  
{
    DataContext GetDataContext();
    
  }
DataContextFactory
  public   class  DataContextFactory : IDataContextFactory
  
{
    
    
private  ConstructorInfo constructorInfo;
    
private  ConstructorInfo mappingSourceConstructorInfp;
    
private Type _dataContextType;
    
private IDbProvider dbProvider;

    
public DataContextFactory(IDbProvider dbProvider, Type dataContextType)
    
{
      
this.dbProvider = dbProvider;
      constructorInfo 
= dataContextType.GetConstructor(new Type[] typeof(IDbConnection) });
      mappingSourceConstructorInfp 
= dataContextType.GetConstructor(new Type[] typeof(IDbConnection), typeof(MappingSource) });
      _dataContextType 
= dataContextType;
    }

 
    
public MappingSource MappingSource
    
{
      
get;
      
set;
    }

    
public IDbProvider DbProvider
    
{
      
get return dbProvider; }
      
set { dbProvider = value; }
    }


    
public bool DefaultDeferredLoadingEnabled
    
{
      
get;
      
set;
    }

    
public bool DefaultObjectTrackingEnabled
    
{
      
get;
      
set;
    }



    
public DataContext GetDataContext()
    
{
      DataContext dc 
= null;
      ConnectionTxPair pair 
= ConnectionUtils.GetConnectionTxPair(DbProvider);
      
if (MappingSource != null )
      
{
          dc 
= (DataContext)constructorInfo.Invoke(new object[] { pair.Connection, MappingSource });
      }

      
else
      
{
        dc 
= (DataContext)constructorInfo.Invoke(new object[] { pair.Connection });
      }

      dc.DeferredLoadingEnabled 
= DefaultObjectTrackingEnabled;
      dc.ObjectTrackingEnabled 
= DefaultObjectTrackingEnabled;
      dc.Transaction 
= (DbTransaction)pair.Transaction;
      
return dc;
    }


    
  }
LocalDataContextFactoryObject 主要用于配置, 它现在提供DataContextFactory的singleton实例,如上面所说,有时它不是必须的,它也会重复一些配置代码



DataContextTemplate 是一个重要的类, 它依赖IDataContextFactory, 并常用的数据方法, 如FindById,FindListById,Delete,Save,Update,之类的这里只摘录主要部分
public   delegate   object  DoInDataContext(DataContext db);

  
public   class  DataContextTemplate
  
{
    
private IDataContextFactory dataContextFactory;
    
public IDataContextFactory DataContextFactory
    
{
      
get return dataContextFactory; }
      
set { dataContextFactory = value; }
    }

   
    
public  void Execute(DoInDataContext doInDataContext){
      
using (DataContext db = dataContextFactory.GetDataContext())
      
{

        doInDataContext(db);
      }

   
    }

    
public  object Find(DoInDataContext doInDataContext)
    
{
      
using (DataContext db = dataContextFactory.GetDataContext())
      
{

        
return doInDataContext(db);
      }

    }

.
}



btw:

1. 我使用spring.net cvs上的代码,目前,如果要像我这样声明DbProvider ,则需要在应用程序启动前 加如下一行

  NamespaceParserRegistry.RegisterParser( typeof (DatabaseNamespaceParser));

2. IFactoryObject接口是spring的魔术接口之一, 当你从spring ioc获取一个实现该接口的对象时,它返回的并不是对象本身,而是IFactoryObject.GetObject方法返回的具体对象. 如果你要获取对象本身,则需要在对象id前加&

你可能感兴趣的:(spring)