如何使用 Entity Framework Core 保存字符串列表?

2024-05-26

假设我们有一个如下所示的类:

public class Entity
{
    public IList<string> SomeListOfValues { get; set; }

    // Other code
}

现在,假设我们想要使用 EF Core Code First 来持久化这一点,并且我们正在使用像 SQL Server 这样的 RDMBS。

一种可能的方法显然是创建一个包装类Wraper包裹字符串:

public class Wraper
{
    public int Id { get; set; }

    public string Value { get; set; }
}

并重构该类,使其现在依赖于以下列表Wraper对象。在这种情况下,EF 将生成一个表Entity,一个表Wraper并建立“一对多”关系:每个实体都有一群说唱歌手。

虽然这可行,但我不太喜欢这种方法,因为出于持久性问题,我们正在更改一个非常简单的模型。事实上,只考虑领域模型和代码,没有持久性,Wraper课堂在那里毫无意义。

除了创建包装类之外,还有其他方法可以使用 EF Core Code First 将具有字符串列表的实体持久保存到 RDBMS 中吗?当然,最终必须做同样的事情:必须创建另一个表来保存字符串,并且必须建立“一对多”关系。我只想使用 EF Core 执行此操作,而不需要在域模型中编写包装类。


EF Core 8 更新

.NET 8 现在内置支持在列中存储基本类型列表。在这里阅读有关原始集合 https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew#primitive-collections.

EF Core 8 之前的版本(或者如果您想手动控制序列化而不是使用 JSON)

从 Entity Framework Core 开始,可以通过更简单的方式实现这一点2.1。 EF 现在支持价值转换 https://learn.microsoft.com/en-us/ef/core/modeling/value-conversions专门解决此类需要将属性映射到不同类型进行存储的场景。

要保留字符串集合,您可以设置DbContext通过以下方式:

protected override void OnModelCreating(ModelBuilder builder)
{
    var splitStringConverter = new ValueConverter<IEnumerable<string>, string>(v => string.Join(";", v), v => v.Split(new[] { ';' }));
    builder.Entity<Entity>()
           .Property(nameof(Entity.SomeListOfValues))
           .HasConversion(splitStringConverter);
} 

请注意,此解决方案不会让您的企业级充满数据库问题。

不用说,这种解决方案必须确保字符串不能包含分隔符。当然,任何自定义逻辑都可以用于进行转换(例如从 JSON 到 JSON 的转换)。

另一个有趣的事实是空值是not传递到转换例程中,而是由框架本身处理。因此,无需担心转换例程内的空检查。然而,整个财产变成null如果数据库包含NULL value.

价值比较器怎么样?

使用此转换器创建迁移会导致以下警告:

属性“Entity.SomeListOfValues”是具有值转换器但没有值比较器的集合或枚举类型。设置值比较器以确保正确比较集合/枚举元素。

为建议的转换器设置正确的比较器取决于列表的语义。例如,如果你不关心其元素的顺序,您可以使用以下比较器:

new ValueComparer<IEnumerable<string>>(
    (c1, c2) => new HashSet<string>(c1!).SetEquals(new HashSet<string>(c2!)),
    c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
    c => c.ToList()
);

使用此比较器,具有相同元素的重新排序列表不会被检测为更改,因此可以避免与数据库的往返。有关值比较器主题的更多信息,请考虑docs https://learn.microsoft.com/en-us/ef/core/modeling/value-comparers?tabs=ef5.

更新 EF Core 6.0

为了受益于Entity Framework Core 6.0 编译模型 https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-5-compiled-models/,我们可以使用通用重载HasConversion。所以完整的图就变成了:

builder.Entity<Foo>()
    .Property(nameof(Foo.Bar))
    .HasConversion<SemicolonSplitStringConverter, SplitStringComparer>();

...

public class SplitStringComparer : ValueComparer<IEnumerable<string>>
{
    public SplitStringComparer() : base(
        (c1, c2) => new HashSet<string>(c1!).SetEquals(new HashSet<string>(c2!)),
        c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())))
    {
    }
}

public abstract class SplitStringConverter : ValueConverter<IEnumerable<string>, string>
{
    protected SplitStringConverter(char delimiter) : base(
        v => string.Join(delimiter.ToString(), v),
        v => v.Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries))
    {
    }
}

public class SemicolonSplitStringConverter : SplitStringConverter
{
    public SemicolonSplitStringConverter() : base(';')
    {
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Entity Framework Core 保存字符串列表? 的相关文章

  • 没有强命名的代码签名是否会让您的应用程序容易被滥用?

    尝试了解authenticode代码签名和强命名 我是否正确地认为 如果我对引用一些 dll 非强命名 的 exe 进行代码签名 恶意用户就可以替换我的 DLL 并以看似由我签名但正在运行的方式分发应用程序他们的代码 假设这是真的 那么您似
  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • 为什么 C# Array.BinarySearch 这么快?

    我已经实施了一个很简单用于在整数数组中查找整数的 C 中的 binarySearch 实现 二分查找 static int binarySearch int arr int i int low 0 high arr Length 1 mid
  • 如何使用 ICU 解析汉字数字字符?

    我正在编写一个使用 ICU 来解析由汉字数字字符组成的 Unicode 字符串的函数 并希望返回该字符串的整数值 五 gt 5 三十一 gt 31 五千九百七十二 gt 5972 我将区域设置设置为 Locale getJapan 并使用
  • HTTPWebResponse 响应字符串被截断

    应用程序正在与 REST 服务通信 Fiddler 显示作为 Apps 响应传入的完整良好 XML 响应 该应用程序位于法属波利尼西亚 在新西兰也有一个相同的副本 因此主要嫌疑人似乎在编码 但我们已经检查过 但空手而归 查看流读取器的输出字
  • 关于 C++ 转换:参数 1 从“[some_class]”到“[some_class]&”没有已知的转换

    我正在研究 C 并且遇到了一个错误 我不知道确切的原因 我已经找到了解决方案 但仍然想知道原因 class Base public void something Base b int main Base b b something Base
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • C# 中通过 Process.Kill() 终止的进程的退出代码

    如果在我的 C 应用程序中 我正在创建一个可以正常终止或开始行为异常的子进程 在这种情况下 我通过调用 Process Kill 来终止它 但是 我想知道该进程是否已退出通常情况下 我知道我可以获得终止进程的错误代码 但是正常的退出代码是什
  • 带动态元素的 WPF 启动屏幕。如何?

    我是 WPF 新手 我需要一些帮助 我有一个加载缓慢的 WPF 应用程序 因此我显示启动屏幕作为权宜之计 但是 我希望能够在每次运行时更改屏幕 并在文本区域中显示不同的引言 这是一个生产力应用程序 所以我将使用非愚蠢但激励性的引言 当然 如
  • 重载<<的返回值

    include
  • 显示UnityWebRequest的进度

    我正在尝试使用下载 assetbundle统一网络请求 https docs unity3d com ScriptReference Networking UnityWebRequest GetAssetBundle html并显示进度 根
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 覆盖子类中的字段或属性

    我有一个抽象基类 我想声明一个字段或属性 该字段或属性在从该父类继承的每个类中具有不同的值 我想在基类中定义它 以便我可以在基类方法中引用它 例如覆盖 ToString 来表示 此对象的类型为 property field 我有三种方法可以
  • 链接器错误:已定义

    我尝试在 Microsoft Visual Studio 2012 中编译我的 Visual C 项目 使用 MFC 但出现以下错误 error LNK2005 void cdecl operator new unsigned int 2
  • 哪种 C 数据类型可以表示 40 位二进制数?

    我需要表示一个40位的二进制数 应该使用哪种 C 数据类型来处理这个问题 如果您使用的是 C99 或 C11 兼容编译器 则使用int least64 t以获得最大的兼容性 或者 如果您想要无符号类型 uint least64 t 这些都定
  • 如何将服务器服务连接到 Dynamics Online

    我正在修改内部管理应用程序以连接到我们的在线托管 Dynamics 2016 实例 根据一些在线教程 我一直在使用OrganizationServiceProxy out of Microsoft Xrm Sdk Client来自 SDK
  • Windows 和 Linux 上的线程

    我在互联网上看到过在 Windows 上使用 C 制作多线程应用程序的教程 以及在 Linux 上执行相同操作的其他教程 但不能同时用于两者 是否存在即使在 Linux 或 Windows 上编译也能工作的函数 您需要使用一个包含两者的实现
  • C++ 标准是否指定了编译器的 STL 实现细节?

    在写答案时this https stackoverflow com questions 30909296 can you put a pimpl class inside a vector我遇到了一个有趣的情况 这个问题演示了这样一种情况

随机推荐