使一个Entity Framework模型跨越多个数据库

29

在 IT 技术中,执行以下操作是否有效:

CREATE SYNONYM [dbo].[MyTable] FOR [AnotherDatabase].dbo.[MyTable]

然后修改 Entity Framework 的 edmx 文件以像任何其他表一样读取此对象?我进行了一个快速的示例测试,在选择和更新方面似乎运行良好,但我想知道是否有任何理由不应该这样做。

我通过创建指向第二个数据库的 edmx 文件并在那里构建实体来获取表定义,然后将定义复制/粘贴到第一个数据库的 edmx 文件中。

更新

如果有人感兴趣,我写了一篇文章介绍如何让 edmx 文件跨越多个数据库here。其中包括生成同义词和合并 edmx 文件的脚本。


1
我看到的主要缺点是需要手动操作edmx,并且失去了自动更新edmx以拉取db模式更改的能力。可能还有其他缺点。 - camainc
1
@carmainc:这只是一个小烦恼,但对我来说,它比手动创建两个数据上下文之间的链接并多次访问服务器以获取链接数据要好。相反,我只需要更新我的第二个edmx文件并复制/粘贴新信息即可。 - Rachel
Rachel,我看到了你的帖子。除了你在帖子中列出的问题之外,是否还遇到了其他问题呢?我在考虑你针对我们公司正在开发的ERP所采取的方法...谢谢! - johnildergleidisson
很高兴你喜欢它!我还没有遇到过任何问题,但是由于我自己对EF还比较新,也还没有用它做过什么高级应用。唯一需要有一天修复的问题是合并脚本需要考虑已删除的项目。我知道如何修复它,但由于我还没有需要使用它,所以我还没有更新脚本。 - Rachel
你是救命恩人! :) - Bedir Yilmaz
如果您更改了具体的模型实体,例如添加Tostring()方法,则edmx的任何更新也会覆盖这些更改。因此,更新edmx的能力是我很久以前就放弃的东西... :) - Kurt Van den Branden
3个回答

11

如果你进行了一项测试并且它成功了,那么你可能展示了一些其他人不知道的东西。直到现在,我总是回答这种类型的问题:不可能使用单个模型连接两个数据库(可以通过视图隐藏第二个数据库中的表格等一些更加丑陋的解决方案)。现在我知道了两种解决方法。

这种方法唯一的缺点是,如果运行 从数据库更新模型,所有手动对 EDMX 的 SSDL 部分所做的更改都会被丢失。这意味着要么手动开发 EDMX(这是相当困难的工作),要么使用某些工具/脚本,在每次从数据库更新后添加你的更改。


1
你不知道这件事让我觉得这个想法可能有问题…… 我还以为你对EF的所有东西都非常了解呢!:) 谢谢你的回复。 - Rachel
这更多是关于了解数据库服务器的功能,我并不完全了解EF。我还在学习中... - Ladislav Mrnka
2
我实际上编写了一个脚本,可以合并edmx文件而不会覆盖您所做的更改。因此,我的最终结果是一个项目持有我的工作edmx,一个项目持有我的第二个数据库的edmx,以及第三个项目运行一个脚本,将edmx#2与edmx#1合并。 - Rachel
@Rachael,这正是我刚刚实现的(将两个edmx合并成一个新的第三个),我估计它可以工作,但直到现在我才有证据。 :-) - Danny Varod
我认为答案应该提到将更多的模式添加到EF搜索要添加的对象的模式列表中 - 作为解决方案。 - Veverke

2
您也可以通过视图实现这一点(如果另一个数据库位于不同的服务器上则需要使用链接服务器)。这样可以避免管理/合并两个单独的edmx文件。我已经使用链接服务器从第二个位于不同服务器上的数据库中读取数据,但我进行了一些快速测试以确定更新/插入/删除是否可行,它们是可以的。
我完全没有分布式事务的经验,因此与分布式事务相关的信息可能好坏参半。如果您的两个数据库位于同一服务器上,我认为分布式事务不再适用。
在使用链接服务器时,有几件事情需要记住:
1. 当您修改链接数据库表中的实体并在上下文上调用“SaveChanges”时,它将尝试启动分布式事务,因此除非有人知道如何停止它,否则需要确保两个服务器设置为处理分布式事务。(我认为使用同义词也会是这样)。 2. 在链接服务器上插入具有标识列的实体会抛出异常,因为EF尝试使用“SCOPE_IDENTITY()”获取新ID,但返回值为null。我不知道是否有解决方法,但我在链接服务器上更新或删除具有标识列的实体时没有任何问题。
在SQL Server A上:
1. 创建到ServerB的链接服务器(如果数据库在同一台服务器上,则跳过此步骤)。 2. 为[ServerB].[AnotherDB]中要访问的每个表在[ServerA].[MyDB]中创建一个视图。
在EDMX中:
1. 添加您的视图到edmx文件中。 2. 在设计器中清除每个属性的实体键设置(包括实际主键)。 3. 重置实际主键的实体键。 4. 根据需要添加关联关系。 5. 保存更改。
对于更新/插入/删除:
1. 右键单击.edmx文件并使用xml编辑器打开。 2. 导航到“StorageModel” -> “Schema” -> “EntityContainer”。 3. 查找实体的entityset并删除“DefiningQuery”元素。 4. 找到实体集上的“store:Schema”属性,并删除“store:”,使其成为“Schema”。不要更改它的值。 5. 对于来自链接服务器的每个视图,重复步骤3和4。 6. 保存更改。
由于使用链接服务器会创建分布式事务,因此在“SaveChanges”成功之前,我必须在ObjectContext上做一些事情。
ctx.Connection.Open();
ctx.ExecuteStoreCommand("set xact_abort on");
ctx.SaveChanges();
ctx.Connection.Close();

你可以创建一个自定义的ObjectContext并重写SaveChanges来添加这些内容。


1
那就是我不想做的事情...这需要大量额外的工作。你需要创建你的视图,创建你的主键,找到并修改DefiningQuery,并重新创建任何存在于你的链接数据库上的链接。我宁愿只更新我的EDMX文件并运行合并脚本(即使对于那些不太了解EF的人来说,也可以使维护变得简单易行)。如果你的数据库不支持同义词,这是一个很好的信息。 - Rachel

1
我发现同义词的这个技巧在"Code first"方法中非常完美,不需要使用edmx文件进行任何操作!
唯一需要做的事情就是将你的类与DataContext的适当同义词进行“绑定”。
例如,如果我在另一个数据库中有一个到表Personnel 的同义词(类名也是Personnel),同义词的名称是"myschema.MySynonym",那么OnModelCreating方法应该如下所示:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema("myschema");

        modelBuilder.Entity<Personnel>()
            .ToTable("MySynonym");

        Database.SetInitializer<TestSynonymContext>(null);

        base.OnModelCreating(modelBuilder);
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接