在EntityFramework中,我们可以通过ToTable("表名")指定表名进行映射,EntityFramework会根据指定的表名构建SQL语句,如果在这里加上数据库名和Schema名(也就是ToTable("数据库.dbo.表名")),是不是可以实现跨数据库查询呢?
于是,我们根据这个思路进行了试验,结果发现了EntityFramework不能进行跨数据库查询的秘密:EntityFramework会对ToTable()中指定的表名进行处理,加上中括号,如果没有指定Schema名,会在表名前加上[dbo],比如:ToTable("表名"),SQL语句中的表名是[dbo].[表名]。而在加“中括号”时的不正确有处理,成为了罪魁祸首。
后来仔细想想,从理论来讲,实现跨数据库查询应该不难啊,与非跨数据库查询相比,只是多了个数据库名,比如下面的非跨数据库查询语句:
SELECT[Text]FROMdbo.blog_PostBodyWHEREID=3560
跨数据库查询语句:
SELECT[Text]FROMCNBlogsText.dbo.blog_PostBodyWHEREID=3560
我们试图组装一些特殊字符串骗过EntityFramework,都没成功。目前我们在用Reflector在EntityFramework的代码中寻找凶手,只有找到了凶手,知道了作案手段,才能知道是否有可能解决这个问题。
下面用代码爆一下料:
BlogDbContext的代码:
LINQtoEntities查询代码:
1.这是非跨数据库查询的情况,生成的SQL语句如下:
指定的表名是blog_PostBody,SQL语句中变成了[dbo].[blog_PostBody]。
2.跨数据库查询:
BlogDbContext的代码改为:
modelBuilder.Entity
生成的SQL语句:
CNBlogsText.dbo被整个加在了中括号中,正确的应该是[CNBlogsText].[dbo].[blog_PostBody]。
试图欺骗一下EntityFramework,将表名改为:
modelBuilder.Entity
生成的SQL语句:
多出了半个中括号,欺骗失败...
这里通过Reflector对EntityFramework的代码进行分析,找出了真相。
真相如下:
1.对于“CNBlogsTex.dbo.blog_PostBody"字符串,EntityFramework对其进行了拆分,拆分为:Schema名称(CNBlogsTex.dbo)与数据库表名称(blog_PostBod)。
这部分是在System.Data.Entity.ModelConfiguration.Utilities.ObjectExtensions的ParseQualifiedTableName()方法中处理的,Reflector出来的代码如下:
2.方括号的添加(CNBlogsTex.dbo变为[CNBlogsTex.dbo],blog_PostBod变为[blog_PostBod])是在System.Data.SqlClient.SqlDdlBuilder的AppendIdentifier(stringidentifier)方法中处理的,Reflector出来的代码如下:
所以,当我们当表名改为"CNBlogsText].[dbo.blog_PostBody"时,"CNBlogsText].[dbo"就被转换为"[CNBlogsText]].[dbo]"。
不仅有代码有真相,而且有图有真相:
知道了真相,目前只能望真相心叹,能不能解决这个问题还是未知数...
更新:
killkill的一句回复让“心叹”变成了“兴奋”,那种程序员特有的,一般人享受不到的兴奋...
原来要欺骗的不是EntityFramework,而且是SQLServer,用SQLServer的同义词(SYNONYM)可以轻松搞定这个问题,创建同义词的SQL语句如下:
CREATESYNONYM[dbo].[CNBlogsText__blog_PostBody]FOR[CNBlogsText].[dbo].[blog_PostBody]
小编结语:
更多内容尽在课课家教育!
¥48.00¥180.00
¥48.00¥180.00
¥798.00
¥199.00
¥199.00
¥29.90