【发布时间】:2020-06-28 19:18:54
【问题描述】:
有没有办法用 Entity Framework Core 填充字典属性?
出于性能原因,我们喜欢在应用程序而不是数据库中进行搜索。由于列表不能很好地扩展,我们喜欢使用字典。
例如(简化示例)
class Course
{
public Dictionary<string, Person> Persons { get; set; }
public int Id { get; set; }
}
class Person
{
public string Firstname { get; set; }
public string Lastname { get; set; }
}
我尝试过的事情
- 天真地添加一个字典属性。这将导致以下错误:
System.InvalidOperationException:无法映射属性“Persons”,因为它属于“字典”类型,不是受支持的原始类型或有效的实体类型。显式映射此属性,或使用“[NotMapped]”属性或使用“OnModelCreating”中的“EntityTypeBuilder.Ignore”忽略它。
-
尝试添加value conversion(与
HasConversion),但转换仅适用于单个项目而不适用于集合。HasMany已经给出了编译错误:builder .HasMany<Person>(c => c.Persons) //won't compile, Persons isn't a IEnumerable<Person> .WithOne().HasForeignKey("PersonId"); 创建一个自定义集合类(继承自
Collection<T>并实现InsertItem、SetItem等)——不幸的是,这也不起作用,因为 EF Core 会将项目添加到集合中,然后首先这将填充属性(至少使用我们的 OwnsOne 属性,在演示案例中没有) - 之后不会调用SetItem。-
添加将构建字典的“计算”属性,将不会调用 setter(列表每次都会更新部分值,与上面有点相同)。看看试试:
class Course { private Dictionary<string, Person> _personsDict; public List<Person> Persons { get => _personsDict.Values.ToList(); set => _personsDict = value.ToDictionary(p => p.Firstname, p => p); //never called } public int Id { get; set; } }
当然,我可以在存储库中构建一个字典(使用Repository pattern),但这很棘手,因为我可能会忘记一些部分——而且我真的更喜欢编译时错误而不是运行时错误,以及声明式风格而不是命令式代码.
更新,要明确
- 这不是代码优先方法
- 在 EF Core 中更改映射的想法,因此无需更改数据库。 - 我没有故意标记数据库;)
- 如果我使用
List而不是字典,则映射有效 - 这是数据库中的 1:n 或 n:m 关系(请参阅 HasMany - WithOne)
【问题讨论】:
-
我的回答有帮助吗?如果不让我知道什么不起作用,我误解了什么,或者需要额外的信息/指导,我很乐意提供帮助。
-
你不能添加一个引用表(实体),它的行为就像一个字典吗?
-
看看这个问题:Entity Framework 4 POCO with Dictionary - Chris Moschini 的回答。
-
这个:Store a Dictionary as a JSON string using EF Core 2.1 可能也有兴趣,看来这就是你要找的东西。
-
字典使用哈希桶来查找实体。您可以使用
Hashset<T>并覆盖实体类(Person)的 GetHashCode 和 Equals 方法以依赖于 key 属性,这将导致 similar performance。 Hashset是受支持的集合类型,您可以避免所有麻烦。
标签: c# dictionary entity-framework-core entity-framework-core-3.1