gpt4 book ai didi

.net - 动态更改模型 - 数据库优先

转载 作者:行者123 更新时间:2023-12-04 06:31:08 25 4
gpt4 key购买 nike

我的数据库是使用数据优先方法的带有 EF 6.0 的 MS-SQL。
我正在与数百个数据库同步(表方案是 几乎 在所有数据库上都相同),在需要时动态更改连接字符串。

我的问题是某些数据库的方案与其他数据库略有不同。
在所有这些上,我有一个表 X,它有一个 Y 列,Y 可以是一个位,也可以是一个字节。

sql tables shown

EF 基于具有 Y 列 的数据库生成了一个模型类。定义为字节。 所以在查询的时候,很明显是抛出了异常。

The 'Y' property on table 'X' could not be set to a System.Boolean value. you must set the value to System.Byte.



exception image

有没有办法以数据库优先方法动态更改模型来解决此问题?或者在将返回值分配给模型之前将其转换为一个字节?防止异常?

最佳答案

有一种方法可以在数据库优先中完成这项工作。简而言之:创建两组映射和模型文件,并在配置文件中选择一组。

模型文件

创建 EDMX 时,EF 会创建三个文件:

  • 商店模型 (*.ssdl)。
  • 类(或概念)模型 (*.csdl)。
  • 这两个模型之间的映射 (*.msl)。

  • 这些文件作为资源文件嵌入在编译的程序集中,通常您不需要知道它们的存在。在运行时,EF 将从程序集中加载文件,由配置文件的连接字符串中的资源路径定向,通常看起来像...

    metadata=res://*/...

    可以将另一组资源文件嵌入到程序集中并相应地修改连接字符串,但这需要几个步骤才能实现。

    为简洁起见,我将“映射和模型文件”称为“模型文件”。

    添加两组模型文件

    步骤 1 - 创建第一组

    创建第一组文件只不过是创建一个 EDMX。我使用了一个非常简单的数据库表:

    CREATE TABLE [dbo].[Person](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
    [IsActive] [bit] NOT NULL,
    CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED ([Id] ASC))
    ALTER TABLE [dbo].[Person] ADD CONSTRAINT [DF_Person_IsActive] DEFAULT ((1)) FOR [IsActive]

    在一个简单的 C# 控制台应用程序中,我从这个表中创建了一个 EDMX。

    第 2 步 - 添加部分文件

    在我的情况下只有 Person创建了类:
    public partial class Person
    {
    public int Id { get; set; }
    public string Name { get; set; }
    public bool IsActive { get; set; }
    }

    在EF中,属性 IsActive必须映射到 bit数据库字段,所以不能简单地将它映射到 byte (或 tinyint )字段,正如您已经发现的那样。我们必须添加第二个属性来支持字节字段:
    partial class Person
    {
    public byte IsActiveByte { get; set; }
    }

    主要挑战是如何根据数据类型将这两个属性中的任何一个映射到数据库中的一个字段。

    第 3 步 - 复​​制和修改第二组

    现在,第一组模型文件已嵌入到装配中。我们希望将它们作为常规文件提供,以便复制和修改它们。这可以通过将设置“元数据工件处理”从其默认值(嵌入输出程序集中)临时更改为 来完成。复制到输出目录 .现在构建项目并在 bin/Debug 文件夹中找到三个文件。

    将“元数据工件处理”设置恢复为默认设置,将文件移动到项目的根目录并将它们复制到第二组中。我最终得到了这些文件,其中“BitModel”文件是原始文件:

    BitModel.csdl
    BitModel.msl
    BitModel.ssdl
    ByteModel.csdl
    ByteModel.msl
    ByteModel.ssdl

    ByteModel 文件支持 Person.IsActiveByte属性我做了这些更改(原始行/编辑行):

  • csdl:
    <Property Name="IsActive" Type="Boolean" Nullable="false" />
    <Property Name="IsActiveByte" Type="Byte" Nullable="false" />
  • 固态硬盘:
    <Property Name="IsActive" Type="bit" Nullable="false" />
    <Property Name="IsActive" Type="tinyint" Nullable="false" />
  • 微信:
    <ScalarProperty Name="IsActive" ColumnName="IsActive" />
    <ScalarProperty Name="IsActiveByte" ColumnName="IsActive" />

  • 现在可以删除 BitModel 文件。

    第 4 步 - 将第二组嵌入为资源

    下一步是将 ByteModel 文件添加到项目中,并在其属性中将“Build Action”设置为“Embedded Resource”。重建项目。

    这些文件的嵌入方式与 EF 最初的嵌入方式略有不同。在反汇编程序中检查 .exe 文件显示它们的资源名称是 <namespace>.<filename> ,就我而言: BitOrBye.ByteModel.csdl , 等等。

    步骤 5 - 添加连接字符串

    EF 向项目添加了一个连接字符串,看起来像......

    <add name="DbBitContext" 
    connectionString="metadata=res://*/BitModel.csdl
    |res://*/BitModel.ssdl
    |res://*/BitModel.msl;
    provider=System.Data.SqlClient;
    provider connection string=&quot;data source=.\sql2016;initial catalog=DbBit;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;"
    providerName="System.Data.EntityClient" />

    我复制了这个连接字符串并注释掉了原来的。在复制的连接字符串中,我修改了资源路径:

    <add name="DbBitContext" 
    connectionString="metadata=res://*/BitOrByte.ByteModel.csdl
    |res://*/BitOrByte.ByteModel.ssdl
    |res://*/BitOrByte.ByteModel.msl;
    ... />

    现在程序集已准备好连接到数据库,其中 Person.IsActive字段是 tinyint .属性(property) Person.IsActive不再是映射属性, Person.IsActiveByte是。

    输入前面的连接字符串,上下文映射到 bit字段,因此现在可以使用连接字符串来确定支持哪种类型的数据库,“BitModel”或“ByteModel”。

    限制

    在 LINQ-to-Entities 查询中,只能处理映射的属性。例如,像这样的查询...
    context.People.Where(p => p.Id > 10).Select(p => p.Name).ToList()

    ……没问题。但是当“BitModel”处于事件状态时,像这样的查询...
    context.People.Where(p => p.IsActiveByte == 1).Select(p => p.Name).ToList()

    ...将抛出臭名昭著的 LINQ to Entities 异常中不支持指定类型成员“IsActiveByte”。

    当然你已经有了这个限制。您可能希望将未映射的属性添加到您的类中,以便将 bye 和 bit 属性的值传送到您将在应用程序代码中使用的一个属性。

    一个可能的出路是使用 EntityFramework.DynamicFilters .这个小 gem 使您能够在可以打开和关闭的上下文中定义全局过滤器。因此,可以定义两个全局过滤器...
    modelBuilder.Filter("IsActiveBit", (Person p) => p.IsActive, true);
    modelBuilder.Filter("IsActiveByte", (Person p) => p.IsActiveByte, 1);

    ...您将添加其中一个,具体取决于您连接到的数据库类型,这可以从连接字符串中推断出来。

    关于.net - 动态更改模型 - 数据库优先,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49026155/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com