文章简略:本文测试项目为Silverlight+EF+RIA Service动态切换数据库的问题


通常,Ado.net EntityFramework的数据库连接字符串ConnectionString是存在实体框架所在的类库项目中的配置文件中(.config)的,类似这样:

<connectionStrings>
<add name="{EFName}Entities" connectionString="metadata=res://*/Model1.csdl|
res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;
provider connection string=&quot;data source={IP};
initial catalog=Northwind;persist security info=True;user id=sa;
password={PWD};multipleactiveresultsets=True;App=EntityFramework&quot;"
providerName="System.Data.EntityClient" />
</connectionStrings>

EntityConnection的ConnectionString和以前的Ado.net的ConnectionString是有一些的区别的。有2个新元素,解释下:

             metatata: 指定Entity Framework数据模型的路径,包括CSDL(概念架构定义语言)、SSDL(存储架构定义语言)、MSL(映射规范语言)的路径

             provider: 数据库provider,例如SQLServer的默认Ado.net:System.Data.SqlClient,也可以是其它的数据库例如Oracle、SQLite、MySql等

需要注意的是:EF框架默认寻找的数据库连接数据库字符串不一定是当期类库或者项目,严谨的说法是,解决方案下的启动项目所在的配置文件中寻找连接

这是用配置的方式指定ConnectionString,也可以用代码动态指定Entity framework的数据库连接,用SqlConnectionStringBuilder手动创建:

public partial class EFNameEntities
{
partial void OnContextCreated()
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder
((EntityConnection)Connection).StoreConnection.ConnectionString);
builder.IntegratedSecurity = false;
builder.UserID = "sa";
builder.Password = "";
builder.InitialCatalog = "";
((EntityConnection)Connection).StoreConnection.ConnectionString = builder.ConnectionString;
}
}

这样ConnectionString就写死了,不能满足实际的开发需求,所以还是要用Web.config配置的方式。

下面我们做一个测试,我们在Web.config添加一个数据库连接方式用来测试,关键词叫“MyTestDBConn”

<connectionStrings>
<add name="EFNameEntities" connectionString="metadata=res://*/Model1.csdl|res:
//*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;
provider connection string=&quot;data source=192.168.1.88;
initial catalog=Northwind;persist security info=True;user id=sa;password={};
multipleactiveresultsets=True;App=EntityFramework&quot;"
providerName="System.Data.EntityClient" />
<add name="MyTestDBConn" connectionString="metadata=res://*/Model1.csdl|res:
//*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;
provider connection string=&quot;data source=192.168.1.100;
initial catalog=Northwind_AAA;persist security info=True;
user id=sa;password={PWD};multipleactiveresultsets=True;App=EntityFramework&quot;"
providerName="System.Data.EntityClient" />
</connectionStrings>
在Domain Service中改变EntityFramework的ConnectionString,这儿指定用"MyTestDBConn":
using System.Configuration; [EnableClientAccess()]
public class TestDomainService : LinqToEntitiesDomainService<TestEntities>
{
protected override TestEntities CreateObjectContext()
{
string connection = ConfigurationManager.ConnectionStrings["MyTestDBConn"].ConnectionString;
return new TestEntities(connection);
}
}

这样的确可以在DomainService切换Entity Framework数据库连接ConnectionString,但我如果有好多DomainService怎么办,岂不是每一个都要这样来一下子?第二 个问题是,如何把"MyTestDBConn"作为一个参数传进来?

先解决第一个问题,我们写一个DomainService的基类,继承原来的基类:LinqToEntitiesDomainService,然后让每一个DomainService继承这个新的基类即可

using System;
using System.Data.Objects;
using System.ServiceModel.DomainServices.EntityFramework;
using System.ServiceModel.DomainServices.Server;
using System.Configuration; public abstract class DomainServiceBase<TContext> : LinqToEntitiesDomainService<TContext>
where TContext : ObjectContext, new()
{
protected override TContext CreateObjectContext()
{
string connection = ConfigurationManager.ConnectionStrings["MyTestDBConn"].ConnectionString; Type contextType = typeof(TContext);
object objContext = Activator.CreateInstance(contextType, connection); return objContext as TContext;
} protected override void OnError(DomainServiceErrorInfo errorInfo)
{
// Deal with errors
}
}
//接着,让你的DomainService继承这个基类,不要继承LinqToEntitiesDomainService了
EnableClientAccess()]
public class TestDomainService : DomainServiceBase<TestEntities>
{
//...
}

第二个问题是如何把"MyTestDBConn"这个ConnectionString关键词作为参数传进来?这个问题有点难。上面说的都是在 服务器端指定连接到哪个数据库服务器,如何实现在客户端用户登录的时候,有个下拉框选择数据库服务器,然后在Silverlight客户端把这个参数传递 到服务器端DomainService并连接到指定的数据库服务器?

如果用上面的思路,就是要在DomainService的构造函数上动手,加一个参数string databaseKey,但是这个有点罗嗦。为什么?因为DomainService不是一般的class,它是WCF Service,在DomainService里面的每一个方法就是一个定义了request和response的contract的WCF (Web Service),只不过WCF Ria Services隐藏了这些调用WCF的复杂性,让你感觉在客户端就可以简单的调用DomainService。所以,如果你要给 DomainService的构造函数传一个参数,就要研究一下如何给WCF Service的构造函数传递一个参数的方法,可以用IInstanceProvider和ServiceBehavior来实现,代码见这篇文章。

这里我用另外一个Session的方法来实现更简单,每个客户端session不同,所以在客户端用户登录的时候,有个下拉框选择数据库服务 器,然后在Silverlight客户端把这个参数传递到服务器端DomainService并让Entity framework连接到指定的数据库服务器是可以用Session来实现的。具体方法是在DomainService里加一个SetDatabase函 数设置数据库,客户端把参数传给服务端,并保存到Session。然后重载CreateObjectContext ()函数并根据Session的值连接到指定的数据库。最后在SetDatabase这个函数的Callback时读取真正的数据。代码:

在DomainService里面加个SetDatabase()方法:

using System.Web;

 [EnableClientAccess()]
public class TestDomainService : LinqToEntitiesDomainService<TestEntities>
{
public void SetDatabase(string Database)
{
HttpContext.Current.Session["UserDatabase"] = Database;
}
} 在DomainService里面重载CreateObjectContext()方法:
using System.Web; [EnableClientAccess()]
public class TestDomainService : LinqToEntitiesDomainService<TestEntities>
{
protected override TestEntities CreateObjectContext()
{
if (HttpContext.Current.Session["UserDatabase"] != null)
{
string connection = ConfigurationManager.ConnectionStrings[HttpContext.Current.Session["UserDatabase"].ToString()].ConnectionString;
return new TestEntities(connection);
}
else
return base.CreateObjectContext();
}
} 前台调用xaml.cs:
public partial class MainPage : UserControl
{
private DomainService1 s = new DomainService1(); public MainPage()
{
InitializeComponent(); //使用MyTestDBConn作为ConnectionString,加载数据到DataGrid
LoadData("MyTestDBConn");
} private void button1_Click(object sender, RoutedEventArgs e)
{
//使用Web.config中另外一个ConnectionString,加载数据到DataGrid
LoadData("YourEntities");
} //EF连接指定的ConnectionString
//Param: database - web.config中ConnectionString的Name关键词
private void LoadData(string database)
{
this.busyIndicator1.IsBusy = true;
//****SetDatabase callback的时候读取数据*********
s.SetDatabase(database, (InvokeOperation) =>
{
//GetCompanies改为你自己的方法
s.Load(s.GetCompaniesQuery(), (t) =>
{
dataGrid1.ItemsSource = t.Entities;
this.busyIndicator1.IsBusy = false;
}, true);
}, null);
}
}

可以另外按照上面DomainServiceBase的方法写一个基类避免每个DomainService重写一遍。

结束

不知道大家有没有更好的方法实现客户端传参到服务端动态切换数据库呢?另:由于Entity framework的模型是由链接到本地数据库映射生成的,所以不提供源码下载了,按照本文的步骤一步步做就能运行。如果对 Silverlight+Wcf Ria service+EF还不明白的,可以看博客园其他的博文。

参考文章:http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/8f18aed8-8e34-48ea-b8be-6c29ac3b4f41

动态切换数据库(EF框架)的更多相关文章

  1. 【TP3.2】 动态切换数据库方法

    1 config 配置: 'connection' => 'mysql://root:root@localhost:3306/dbname', connection  数据库连接字符串,后面代码 ...

  2. 封装了一些sqlsugar的常用方法 用来动态切换数据库和依赖注入 支持泛型

    接口: /// <summary> /// 数据库操作 /// </summary> public interface IDAL_Services { /// <summ ...

  3. jdbc动态切换数据库

    http://www.oschina.net/code/snippet_140474_50797

  4. Spring AOP动态切换数据源

    现在稍微复杂一点的项目,一个数据库也可能搞不定,可能还涉及分布式事务什么的,不过由于现在我只是做一个接口集成的项目,所以分布式就先不用了,用Spring AOP来达到切换数据源,查询不同的数据库就可以 ...

  5. EntityFramework For Mysql 动态切换数据源

    1.简介 在工作中遇到一个问题.项目有三个数据库(三个数据库表结构一样),用户可以选择使用哪个数据库.其实就是动态切换数据库连接. 2.EntityFramework For Mysql 先来简单的介 ...

  6. Spring动态切换多数据源事务开启后,动态数据源切换失效解决方案

    关于某操作中开启事务后,动态切换数据源机制失效的问题,暂时想到一个取巧的方法,在Spring声明式事务配置中,可对不改变数据库数据的方法采用不支持事务的配置,如下: 对单纯查询数据的操作设置为不支持事 ...

  7. Pytest测试框架一键动态切换环境思路及方案

    前言 在上一篇文章<Pytest fixture及conftest详解>中,我们介绍了fixture的一些关键特性.用法.作用域.参数等,本篇文章将结合fixture及conftest实现 ...

  8. C# CodeFirst(EF框架)代码优先创建数据库

    namespace WebEF.Model{ public class ModelContext:DbContext //继承DBcontext 来自EF框架 { public ModelContex ...

  9. Spring3 整合Hibernate3.5 动态切换SessionFactory (切换数据库方言)

    一.缘由 上一篇文章Spring3.3 整合 Hibernate3.MyBatis3.2 配置多数据源/动态切换数据源 方法介绍到了怎么样在Sping.MyBatis.Hibernate整合的应用中动 ...

随机推荐

  1. splay旋转模板

    splay旋转模板 void rotate(int x) { int y=f[x],z=son(x);f[x]=f[y]; if (f[x]) t[f[x]][son(y)]=x; t[y][z]=t ...

  2. 编写可维护的JavaScript----笔记(一)

    1.缩进层级 建议使用4个空格为一个缩进层级,避免使用制表符进行缩进,可以通过配置文本编辑器来改变 缩进层级表示的内容. 2.语句末尾 有赖于分析器的自动分号插入机制(ASI),JavaScript可 ...

  3. Java and unsigned int, unsigned short, unsigned byte, unsigned long, etc. (Or rather, the lack thereof)

    http://darksleep.com/player/JavaAndUnsignedTypes.html —————————————————————————————————————————————— ...

  4. MonoTouch

    本文为2012年4月19日Xamarin研讨会OLO在线咨询高级软件工程师Greg Shackles的一份的演讲资料. 本文为2012年4月19日Xamarin研讨会OLO在线咨询高级软件工程师Gre ...

  5. Prime triplets (Project Euler 196)

    original version hackerrank programming version 题目大意是定义了一个正整数的表,第一行是1,第二行是1,2,第三行1,2,3...定义prime tri ...

  6. jquery监听事件on写法以及简单的拖拽效果

    引子——关于jquery的某些写法 我先不对监听事件做解释,我们先来看下jquery的一些写法吧!我们最常用的是jquery的css()方法,相信大家都会用! 假如用css设置一个属性,我们写法如下: ...

  7. css position float (写的相当好)

    对CSS中的Position.Float属性的一些深入探讨 对于Position.Float我们在平时使用上可以说是使用频率非常高的两个CSS属性,对于这两个属性的使用上面可能大多数人存在一些模糊与不 ...

  8. Django 找不到模版报错" django.template.exceptions.TemplateDoesNotExist: index.html"

    解决办法:在setting.py的TEMPLATES‘DIRS'[]加入模版路径 os.path.join(BASE_DIR, 'templates') TEMPLATES = [ { 'BACKEN ...

  9. xml html xhtml html5

    1.XML 什么是 XML? XML 指可扩展标记语言(EXtensible Markup Language) XML 是一种标记语言,很类似 HTML XML 的设计宗旨是传输数据,而非显示数据 X ...

  10. 判断 null undefined NaN

    1.判断undefined: var tmp = undefined; if (typeof(tmp) == "undefined"){ alert("undefined ...