【问题标题】:Entity Framework Core default values for missing columns缺少列的 Entity Framework Core 默认值
【发布时间】:2019-12-06 21:43:57
【问题描述】:

我有一个 sqlite 数据库,它有一些表和列,如下所示:

int Id
text Name
text Comment
...

我的项目中的对象如下所示:

Public Class Entry {
    public int Id { get; set; }
    public String Name { get; set; }
    public String Comment { get; set; }
    public String Additional { get; set; }
}

这可能发生,因为我的程序需要处理不同版本的数据库。 EF Core 现在尝试访问数据库的Additional 字段,但返回找不到该字段的错误。 (预期行为)

现在我的问题是,是否有办法忽略此错误并返回属性的默认值?

我可以通过使属性为空来绕过错误。但我不想在访问之前使用.HasValue() 检查每个属性。因为真正的数据库在表中有 50+ 列。

【问题讨论】:

    标签: c# entity-framework-core ef-core-2.2


    【解决方案1】:

    https://www.entityframeworktutorial.net/code-first/notmapped-dataannotations-attribute-in-code-first.aspx

    将 NotMapped 作为附加字段的属性:

    using System.ComponentModel.DataAnnotations.Schema;
    
    Public Class Entry {
        public int Id { get; set; }
        public String Name { get; set; }
        public String Comment { get; set; }
    
        [NotMapped]
        public String Additional { get; set; }
    }
    

    这告诉 EF 该字段不是数据库中的列。

    【讨论】:

    • 取决于服务器和客户端的版本差异。服务器发送的列可能比客户端预期的要少。
    • 在您的情况下,服务器是数据库,客户端是您的应用程序吗?还是您指的是 Web 服务器和浏览器客户端?
    • 客户端例如是一个使用sqlite作为本地数据库的windows客户端。服务器创建此数据库并将其提供给客户端。因为客户端必须能够离线工作。如果客户端更新但服务器没有更新,则客户端可能期望数据库中的列不是由服务器提供的。在这种情况下,我不想要异常,而是要获取默认值。
    • 如果您的数据库不包含模型上的字段,则必须将该字段标记为未映射。其他任何东西都是黑客攻击。
    • 你可以看看使用 Entity Framework Fluent API 来做更复杂的逻辑
    【解决方案2】:

    我建议你将你的域对象从那个持久化的 dto 对象中分离出来。这样您就可以拥有具有不同映射的不同 dto。现在您可以使用您的 dto 实例化您的域对象,并在您的域对象内部决定哪些值是正确的默认值。

    public class Entry
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Comment { get; set; }
        public string Additional { get; set; }
    }
    
    public class EntryDtoV1
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Comment { get; set; }
    }
    
    public class EntryDtoV2
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Comment { get; set; }
        public string Additional { get; set; }
    }
    

    现在您只需要创建某种工厂,根据您查询的数据库版本创建正确的存储库。

    【讨论】:

    • 问题如下:客户端尝试访问可能不在 sqlite 数据库中的列。如果服务器的版本比客户端旧,则可能会发生这种情况,
    • 我明白这一点。你在你的工厂处理这个。当然,您的工厂必须知道它适用于哪个服务器版本。这样你就有了一个简洁的设计。
    • 好的,谢谢。这肯定适用于其他版本。但是对于旧版本,我们必须忍受特定版本组合中的一些错误。
    • 不客气 :) 我遇到了类似的问题,首先使用了另一种解决方案。我使用的解决方案一开始很好,但随着时间的推移变得更糟。第二种方法使用了类似于我在这里写的解决方案,直到知道它工作正常,也许将来也会改变;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    • 2021-06-18
    • 1970-01-01
    • 2013-11-02
    • 2016-09-27
    • 1970-01-01
    相关资源
    最近更新 更多