c# - 在 ef core 中实现动态数据模型的最佳方法
问题描述
我有:Ef Core 5、Postgresql和模型:
public class Workitem
{
public Guid Id { get; set; }
public string Caption { get; set; }
public List<Field> Fields { get; set; }
}
public struct Field
{
public Guid Id { get; set; }
public string Caption { get; set; }
public FieldValueType ValueType { get; set; }
public object Value { get; set; }
public override bool Equals(object obj)
=> ReferenceEquals(this, obj) || obj is Field other && this.Value == other.Value;
public override int GetHashCode()
=> Value.GetHashCode();
}
public enum FieldValueType
{
ValueAsString,
ValueAsDate,
ValueAsDatetime,
ValueAsInt,
ValueAsDouble,
ValueAsBool,
ValueAsDictionary
}
我想实现在 Workitem 中存储一组动态字段的能力,而每个字段可以有不同类型的值。我需要一个可以方便地在客户端(应用程序)和数据库服务器端(转换为 SQL 时)使用的解决方案。
db.Workitems.Where(wi => wi.Fields.Any(f =>
(f.ValueType == FieldValueType.ValueAsInt && f.Value >= 2)
|| (f.ValueType == FieldValueType.ValueAsString == "abc"))
.ToList();
或者
new List<Workitem>(){ new Workitem() { Fields = new List<Fields>() { new Field() { ValueType = FieldValueType.ValueAsInt, Value = 1 } } } }
.Where(wi => wi.Fields.Any(f =>
(f.ValueType == FieldValueType.ValueAsInt && f.Value >= 2)
|| (f.ValueType == FieldValueType.ValueAsString == "abc"))
.ToList();
或者
db.Workitem.Add(new Workitem() { Fields = new List<Fields>() { new Field() { ValueType = FieldValueType.ValueAsDatetime, Value = DateTimeOffset.Now } } });
这应该与 IQueryable 和 IEnumerable 一起正常工作
我找到了几种解决方案,但在其中任何一个中都找不到一个方便的解决方案。以前,这是使用EAV实现的,现在一切都倾向于 postgresql 的JSONB列,因为 npgsql 可以使用它们。
我添加了这个配置,但是在反序列化时我已将“值”字段的类型指定为“对象”,我在反序列化时遇到了困难。
public override void Configure(EntityTypeBuilder<Workitem> builder)
{
builder.HasKey(x => x.Id);
builder.Property(x => x.Caption).HasMaxLength(150);
builder.Property(x => x.Fields)
.HasColumnType("jsonb")
.HasConversion(
v => JsonConvert.SerializeObject(v),
v => JsonConvert.DeserializeObject<List<Field>>(v),
new ValueComparer<List<Field>>(
(c1, c2) => c1.SequenceEqual(c2),
c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
c => c.ToList()));
}
我还看到了每种数据类型都有一个单独的字段的实现,但这是一个糟糕的选择。
public struct Field
{
public Guid Id { get; set; }
public string Caption { get; set; }
public FieldValueType ValueType { get; set; }
public string _strValue;
public int? _intValue;
public double? _doubleValue;
...
public dynamic Value //return _<type>Value
}
我想得到一个尽可能方便和简单的解决方案。
解决方案
推荐阅读
- c# - 添加一列以对 ListView 上的行进行编号
- r - 使用 imp4p 包 impute.slsa 函数的缺失值插补错误:fast_apply_sd_na_rm_T(xincomplete1, 1) 中的错误:不是矩阵
- javascript - Cypress:Cypress 自定义命令的返回值实际上在测试文件中返回 null
- java - 在 Jsoup 中解析 html
- ios - PDFKit 和 PDFDocument 注释在 Adobe Acrobat 中不可见
- laravel - 如何使用 vagrant box 修复流明迁移错误
- android - 应用程序在打开 QR Scanner Flutter 时崩溃
- alfresco - 拥有对文档的访客访问权限 - 这是否应该允许用户搜索此文档?
- angular - 我想在 React 表单输入中显示 A$,但只返回数字;
- bash - 如何在 Expect 脚本中循环 Bash 数组