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

use*_*696 18 c# entity-framework entity-framework-core .net-core

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

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

    // Other code
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

    public string Value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

并重构类,以便它现在依赖于Wraper对象列表.在这种情况下,EF会生成一个表Entity,一个表,Wraper并建立一个"一对多"关系:对于每个实体,都有一堆包装器.

虽然这有效,但我不太喜欢这种方法,因为我们正在改变一个非常简单的模型,因为持久性问题.实际上,只考虑领域模型和代码,没有持久性,Wraper类在那里是毫无意义的.

有没有其他方法使用EF Core Code First将一个带有字符串列表的实体持久保存到RDBMS而不是创建一个包装类?当然,最后必须完成同样的事情:必须创建另一个表来保存字符串,并且必须建立"一对多"关系.我只想用EF Core做这个,而不需要在域模型中编写包装类.

Dej*_*jan 16

从Entity Framework Core 2.1开始,这可以通过更简单的方式实现.EF现在支持价值转换专门解决方案这样其中属性需要被映射到不同类型的用于存储.

要保留字符串集合,您可以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);
} 
Run Code Online (Sandbox Code Playgroud)

请注意,此解决方案不会因数据库问题而破坏您的业务类.

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

另一个有趣的事实是,null值不会传递给转换例程,而是由框架本身处理.因此,不需要担心空检查.

  • 此外,这仅在您为属性分配值时才有效:调用`IList.Add` 不会将实体标记为已修改,因此不会保存更改。 (3认同)
  • 一个*确实*必须担心空检查,因为如果你的数据库中有一个空值,`Entity.SomeListOfValues`不会是一个空的枚举,而是一个空的。 (2认同)

hat*_*cyl 3

你是对的,你不想让你的域模型充满持久性问题。事实是,如果您对您的领域和持久性使用相同的模型,您将无法避免这个问题。特别是使用实体框架。

解决方案是,构建域模型时完全不考虑数据库。然后构建一个单独的层来负责翻译。类似于“存储库”模式的东西。

当然,现在你的工作量增加了一倍。因此,您需要在保持模型整洁和完成额外工作之间找到适当的平衡。提示:在更大的应用程序中,额外的工作是值得的。