运行时更改Entity Framework数据库架构

10
在大多数asp.net应用程序中,您可以通过在运行时修改连接字符串来更改数据库存储方式。例如,我可以通过简单地更改连接字符串中"database"字段的值,从使用测试数据库切换到生产数据库。
我正在尝试使用实体框架更改模式(但不一定是数据库本身),但没有成功。
我看到的问题是edmx xml文件中SSDL内容存储了每个entityset的模式。
请参见下面的内容:
<EntitySet 
    Name="task" 
    EntityType="hardModel.Store.task" 
    store:Type="Tables" 
    Schema="test"  />

现在我已经将模式属性值从测试更改为“prod”,它可以正常工作。

但这似乎不是一个好的解决方案。

  1. 我需要更新每个实体集以及存储过程(我有50多个表)
  2. 我只能在编译时执行此操作吗?
  3. 如果我后来尝试更新实体模型-由于EF未能识别EDM中已存在的表,因此已经存在的实体将被读取。

有什么想法吗?


要明确的是,我确实在不同的服务器上拥有生产和测试环境。实际情况是,我想从一个机器上运行我的应用程序的两个版本,每个版本应该在一个单独的“模式”/数据库上运行。EF将模式名称存储为EF ssdl文件的一部分,并使用此设计时模式生成SQL查询,但由于无法保证模式的名称相同,因此这些查询将失败。相关 - https://dev59.com/0EjSa4cB1Zd3GeqPKPsU - user48545
我最终使用了这个 https://dev59.com/S2Ik5IYBdhLWcg3wPL_R - Nick
8个回答

6
我也遇到了同样的问题,这真的很令人烦恼,因为这是微软错失机会的典型案例。使用EF的一大原因是支持其他数据库,但除非你使用"Code First",否则无法解决此问题。
在MS SQL中更改模式几乎没有意义,因为模式是表的身份的一部分。对于其他类型的数据库,模式不是数据库身份的一部分,只确定数据库的位置。在连接Oracle时,更改数据库和更改模式基本上是同义词。

2
我也是因为Oracle的情况而来到这里,到目前为止,我只能手动编辑RAW .edmx文件以删除entityset节点中的Schema部分,以及在生成的SQL语句中...虽然它可以工作,但这是一种糟糕的做事方式。 - Dylan Hayes

2
抱歉,这不是一个完整的答案,但当我在谷歌上搜索类似问题时,在codeplex上找到了这个项目(以及这个问题):

http://efmodeladapter.codeplex.com/

该项目的特点包括:

  • 运行时调整模型架构,包括:
  • 调整数据级别表格前缀或后缀
  • 调整数据库对象的所有者

以下是文档中的一些代码:

public partial class MyObjectContext : BrandonHaynes.ModelAdapter.EntityFramework.AdaptingObjectContext
{
        public MyObjectContext() 
        : base(myConnectionString, 
        new ConnectionAdapter(
            new TablePrefixModelAdapter("Prefix", 
                new TableSuffixModelAdapter("Suffix")), 
        System.Reflection.Assembly.GetCallingAssembly()))
    {
    ...
    }

看起来这正是您要找的东西。


嗨,jfar, 这很有趣...不确定它是否解决了我的问题,因为我还没有测试过。但如果它能做到“用法”所说的那样,那就很酷了。在mysql和mssql中,“schema”的含义差异使得这个问题难以测试。我正在从没有这个问题的mysql迁移到mssql。 - user48545

2
解决问题最简单的方法是手动从模型的SSDL部分中删除所有类似'Schema="SchemaName"'的条目。
在这种情况下,一切都可以正常工作。

好的,我已经完成了。问题是在我更新模型后,模式属性会重新出现。是否有一种“更难”的解决方案,在我尝试更新模型时不会出现问题? - user48545
这是 Microsoft Update Model from database wizard 的已知限制 - 它会覆盖对存储模型(SSDL)进行的所有手动更改。 使用 dotConnect for MySQL 的用户可以使用 Entity Developer 工具(它允许在设计时编辑 EF 模型,并且不会出现上述问题)。抱歉,但 Entity Developer 不支持 MySQL Connector/NET。 - Devart
FYI - 我正在使用 dotConnect for MySQL,但不是 Entity Developer 工具。 - user48545

2
更新:根据您的评论,很明显您想要更改每个数据库引用的模式,而不是更改数据库本身。我编辑了问题以澄清这一点,并恢复了您提供的示例EDMX,该示例在原始格式中被隐藏。
我会在下面重复我的评论:
如果架构位于同一个DB中,则无法在运行时切换这些架构(除非使用EF 4代码)。这是因为两个具有相同名称和结构的架构中的表被认为是完全不同的表。
我也同意JMarsch的观点:我会重新考虑将测试数据和生产数据(或实际上是“任何东西和生产数据”)放入同一个数据库的设计。这似乎是灾难的邀请。
旧答案如下。
你确定你在更改正确的连接字符串吗?EF使用的连接字符串嵌入在指定CSDL/SSDL等位置的连接字符串中。通常情况下,应用程序的其他部分(例如ASP.NET成员资格)会使用“普通”的连接字符串。在这种情况下,当更改数据库时,必须更新两个连接字符串。
同样地,如果你在运行时更新连接字符串,则必须使用特定工具,这些工具了解EF连接字符串格式,并且与通常的连接字符串生成器分开。请参见链接中的示例。另请参阅关于分配EF连接字符串的帮助

是的,我实际上正在访问正确的数据库。但问题在于,从 EF 生成的 SQL 在表名前面添加了“设计时”数据库名称。换句话说,我的应用程序正在对 prodfoo 数据库执行“Select * From testfoo.users”,但是 testfoo 是我生成模型时使用的数据库名称,它不在生产服务器上。因此,错误是“找不到对象 testfoo.users..”。 - user48545
testfoo听起来像是一个模式(schema)名称,而不是数据库(database)名称。数据库名称看起来应该像dbname..schemaname.table.你的两个数据库是否有不同的模式(schemas) - Craig Stuntz
我认为你是正确的。我真正想做的是在数据库中切换不同的模式(schema)。一个模式用于生产,另一个模式用于测试。 - user48545
好的,但是这个问题和你所问的完全不同。为什么测试数据库和生产数据库(假设它们实际上是不同的)不能使用相同的模式名称呢? - Craig Stuntz
如果模式在同一个数据库中,你就不能在运行时切换它们(除非使用EF 4仅代码)。这是因为两个在不同模式中具有相同名称和结构的表被认为是完全不同的表 - Craig Stuntz
请注意,这是 Oracle 数据库的合法要求,其中所有表都被扔在一个巨大的堆中,“模式”兼作 DB 分隔符。 - Captain Kenpachi

1

EF的连接字符串在配置文件中。无需更改SSDL文件。

编辑

您的生产环境和测试环境是否在同一个数据库中?

如果是,您可以通过为生产和测试使用不同的数据库来解决此问题。在两个数据库中使用相同的模式名称。

如果不是,则可以通过在两个数据库中使用相同的模式名称来解决此问题。

如果您绝对需要不同的模式名称,请创建两个EF模型,一个用于测试,一个用于生产,然后根据配置文件中的值选择要使用的模型。


这个不起作用。这是我“假设”会起作用的..但实体框架并不那么容易。 - user48545
是的,我正在更新正确的配置文件。我创建了一个仅包含一个表和连接字符串的演示解决方案,但我仍然遇到了同样的问题。只是为了澄清一下:更改web.config确实会使EF访问“正确”的数据库。问题在于输出的SQL包含“模式”作为输出SQL的一部分。例如,“从schemaName.tablename选择*”。 - user48545
2
所以你真的需要改变模式,而不是你连接的数据库吗?我讨厌得到这个答案,但它似乎是正确的:也许你应该重新考虑设计。模式实际上是表的身份的一部分。所以,你有点想做的是说“我想在运行时更改所有查询的表的名称。”虽然这是可行的,但并不是非常实用。我同意其他评论者关于将测试数据放在不同的数据库中的观点。 - JMarsch
2
关于将测试数据放在单独的数据库中,还有一个要注意的地方:这样可以为您的测试数据和生产数据分别备份。您可能不想每次重置测试数据时都清除生产数据。我不太了解mysql,但SQL服务器允许在一个服务器上拥有多个数据库。 - JMarsch
实际上,更改相同表的模式名称在需要在后台更新几个大型只读表但不能切换任何表除非您将它们全部切换的情况下非常有用。 - Dave
显示剩余3条评论

1

1
当我创建一个新的“ADO.NET实体数据模型”时,在设计视图中有两个属性“实体容器名称”和“命名空间”可供编辑。使用namespace.EntityContainerName,您可以创建一个新实例并指定连接字符串。
MyEntities e = new MyEntities("connstr"); e.MyTable.Count();
我不确定这是否对您有所帮助,祝你好运!
此外,这是多层的一个很好的案例(不一定是项目,但可以是)。
解决方案 * DataAccess - 在此处实体 * Service - 包装对DataAccess的访问 * Consumer - 调用服务
在这种情况下,消费者调用服务,传递确定使用哪个连接字符串的任何因素。然后,服务实例化数据访问的实例,传递适当的连接字符串并执行消费者的查询。

0

通过从mysql迁移到sql server,解决了我的问题。

Mysql和Mssql以不同的方式解释“schemas”。在mysql中,“schemas”与数据库相同/同义词。当我创建模型时,模式名称(与数据库名称相同)硬编码在生成的模型xml中。在Mssql中,模式默认为“dbo”,但这不是问题,因为在mssql中,模式和数据库是不同的。


更换数据库供应商并不是任何人的真正答案,甚至包括你在内,你应该将其作为评论添加,而不是作为答案... - VoidMain

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