【问题标题】:EntityFramework database first - type mapping - map binary(8) from SQL to int in C#EntityFramework 数据库第一类型映射 - 将二进制(8)从 SQL 映射到 C# 中的 int
【发布时间】:2016-07-29 07:35:20
【问题描述】:

在 SQL 内部,我有一个主键为二进制 (8) 的表。当我使用 Update Model from Database 将该表添加到我的模型中时,我可以看到该列的 type=Binary

在 C# 中,我将该列设为 byte[]

我可以将该列映射到 int 吗?

我知道我可以在 SQL 中使用CAST 创建一个视图:

SELECT
    Client_Id,
    CAST(Client_Id AS INT) AS NewClient_Id,
    * /*other columns*/
FROM
    dbo.Clients

但这不是解决方案,因为我必须能够写入,而不仅仅是从该表中读取。我知道我可以为插入创建存储过程,但我想避免这种情况。

我使用的是 EntityFramewor 6.1.3。

【问题讨论】:

  • 您是否也要尝试将一夸脱放入品脱罐中? binary(8) 包含 8 个字节。 C# 中的 int 包含 4 个字节。你看到这里的问题了吗?
  • @Damien_The_Unbeliever 抱歉,如果我写的东西不正确,但我正在努力让它发挥作用。我想如果我可以在 SQL 中执行CAST,那么也许 EF 可以为我执行该转换。我可以自己在代码中将 byte[] 转换为 int,但我认为 EF 有这个内置,我只是不知道如何打开或配置它。
  • 您可以写入视图。但是,您需要针对您的视图提供触发器,以便将值转换回来。二进制 8 也是一个很长的 IIRC
  • @Mark 我已经尝试将 int 值插入到该二进制文件(8)中,并且 SQL 正在为我转换该值,如果我在该表中插入 2 作为 ClientId,我将拥有0x0000000000000002。我想避免视图和过程,因为我想在现有表中使用相同的方法(将 binary(8) 转换为 int)而不创建额外的 20 个视图。
  • 两个属性是可能的解决方案吗? Convert value when mapping

标签: c# entity-framework entity-framework-6


【解决方案1】:

你有 3 种不同的解决方案

x 存储过程,但您不想要它们。

x 将未映射的属性添加到您的类。此解决方案的最大问题是您无法使用未映射属性进行查询。您必须将所有数据读取到客户端,然后将条件应用于客户端上的非映射属性(因此您的应用不可扩展)。

[NotMapped]
public long LongClientId
{
    get { return BitConverter.ToInt64(this.ClientId, 0); }
    set { this.ClientId = BitConverter.GetBytes(value); }
}

此查询无效

context.MyDbSet.Where(m => m.LongClientId == 12).ToList();

你需要这样改

context.MyDbSet.ToList().Where(m => m.LongClientId == 12);

此查询的结果是您将所有表的记录(从 dbms 传输到您的应用程序)加载到一个列表中,而不是您需要的。

x 创建一个视图(可能是索引视图)并使用 INSTEAD OF 触发器。

【讨论】:

  • 我在 GitHub 上的 EF 存储库中创建了问题,因为我想要获得的内容目前在 EF6 和 EF Core 中是不可能的。我可能会选择第三种解决方案,因为我不想将整个表加载到内存中(ToList 会这样做)。存储过程也会做同样的事情,所以视图现在看起来是最好的解决方案。我将保持开放状态,也许有更好的解决方案。
【解决方案2】:

我知道为什么你在数据库结构和页面的 c# 代码中都不坚持使用 int 或 byte

【讨论】:

    【解决方案3】:

    根据我的经验,映射过程很容易混淆,尤其是在更新现有地图时。因此,我建议您使用

    long CurrentClientId = BitConverter.ToInt64(Rec.ClientId) 
    

    在阅读和

    Rec.ClientId = BitConverter.GetBytes(CurrentClientId) 
    

    在写。您可能已经有一个包装器来处理记录,因为它们被读入内部结构,这只是一个步骤。

    请注意,这并没有注意您可能认为您在字节数组中具有的字节顺序,但至少该过程将正确往返。

    【讨论】:

      【解决方案4】:

      您可以在模型内部处理转换,如下所示:

          [NotMapped]
          public long ClientId
          {
              get { return BitConverter.ToInt64(this.ClientIdBytes, 0); }
              set { this.ClientIdBytes = BitConverter.GetBytes(value); }
          }
      
          [Column("ClientId")]
          public byte[] ClientIdBytes { get; set; }
      

      调用者使用 ClientId 作为 long,但此属性未映射到数据库。 getter 和 setter 只是将值转换为第二个属性,该属性会持久保存在 ClientId 数据库列名中。

      【讨论】:

      • 这是唯一的方法,但您不能使用 ClientId 字段(即 context.MyTable.Where(e => e.ClientId == 1) )将 LINQ 写入实体查询。您必须阅读所有表格而不是应用条件(即 context.MyTable.ToList().Where(e => e.ClientId == 1) )
      • 感谢您的建议,但我想避免将整个表加载到内存中
      猜你喜欢
      • 2015-11-15
      • 1970-01-01
      • 1970-01-01
      • 2020-05-13
      • 1970-01-01
      • 2020-05-16
      • 1970-01-01
      • 2012-10-08
      • 2020-01-01
      相关资源
      最近更新 更多