efcore 更新关联表_.NET:使用 LinqSharp 表设计数据注解

c495043b4eb4ab72cf9e3e4f57804674.png

LinqSharp 是个开源 LINQ 扩展库,它允许您编写简单代码来生成复杂查询,包括查询扩展和动态查询生成。

LinqSharp.EFCore 是对 EntityFramework 的增强库,提供更多数据注解、数据库函数及自定义储存规则等。

LinqSharp:为 LINQ 提供更多通用扩展​github.com

由于内容较多,将分篇介绍公开内容、原理及案例分享:

  1. LinqSharp:简化复杂查询
  2. LinqSharp:动态构建 LINQ 查询
  3. LinqSharp.EFCore:表设计数据注解
  4. LinqSharp.EFCore:字段标准化数据注解
  5. LinqSharp.EFCore:函数映射
  6. LinqSharp.EFCore:列式存储代理
  7. LinqSharp.EFCore:关联计算与审计

数据注解

LinqSharpCodeFirst 模型提供了更多且易于使用的数据注解,分为:

  • 表设计数据注解
  • 数据标准化数据注解

表设计数据注解,是调用 Flunt API 的替代方案,方便编写 CodeFirst 模型。

表设计数据注解

表设计数据注解解析的内部实现是对 Flunt API 进行调用。

因此,生效功能实现,需要重写 DbContext 下的 OnModelCreating 方法:

public class ApplicationDbContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        LinqSharpEF.OnModelCreating(this, base.OnModelCreating, modelBuilder);
    }
}

索引(Index)

索引,是对数据库表中一列或多列值进行排序,以达到快速访问数据库表中的特定数据的能力。

Entity Framework 没有提供索引的数据注解,但在 Flunt API 提供了相应功能。

为了简化设计,LinqSharp 提供了 IndexAttribute 的数据注解实现。

假设,我们要创建这样的表:

  • Id:主键
  • Int0:非聚集索引
  • Int1:唯一索引
  • Int2_G1:和 Int3_G1 组成 唯一索引
  • Int3_G1:和 Int2_G1 组成 唯一索引

dffe2b5b7ddd7fb52f3f0486f873b3f1.png

CodeFirst 模型中使用 IndexAttribute

public class LS_Index
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    [Index(IndexType.Normal)]
    public int Int0 { get; set; }

    [Index(IndexType.Unique)]
    public int Int1 { get; set; }

    [Index(IndexType.Unique, Group = "Int2_G1&Int3_G1")]
    public int Int2_G1 { get; set; }

    [Index(IndexType.Unique, Group = "Int2_G1&Int3_G1")]
    public int Int3_G1 { get; set; }
}

如果使用 MySQL,这段代码会生成如下索引:

ffa3e2c2af369431785469f630adf252.png

自定义数据存储(Provider)

自定义数据存储是为复杂数据提供对象化地解析的功能,内部实现是对 Flunt API - HasConversion 的调用。

例如,设计一个 CodeFirst 模型,满足:

  • 字段 NameModel 读取类型是 NameModel,存储为 JSON
  • 字段 Password 读取值是实际值,存储为 BASE64

使用 ProviderAttribute 为指定字段进行定义:

public class LS_Provider
{
    [Key]
    public Guid Id { get; set; }

    [StringLength(127)]
    [Provider(typeof(PasswordProvider))]
    public string Password { get; set; }

    [StringLength(127)]
    [Provider(typeof(JsonProvider<NameModel>))]
    public NameModel NameModel { get; set; }

    public class PasswordProvider : IProvider<string, string>
    {
        public override string ReadFromProvider(string value) 
            => value.Flow(StringFlow.FromBase64);
        public override string WriteToProvider(string model) 
            => model.Flow(StringFlow.Base64);
    }
}

JsonProviderLinqSharp 的内建转换器,作用是储存 JSON 化。

自定义转换器类需要继承接口 IProvider,其中 TModel 为对象类型,TProvider 为储存类型。

IProvider 接口包含两个方法:

  • “将数据写入储存介质”的转换方法:WriteToProvider(TModel model)
  • “从储存介质读取数据”的转换方法:ReadFromProvider(TModel model)

例如,JsonProvider 的实现:

public class JsonProvider<TModel> : IProvider<TModel, string>
{
    public override TModel ReadFromProvider(string value) 
        => (TModel)JsonConvert.DeserializeObject(value, typeof(TModel));
    public override string WriteToProvider(TModel model) 
        => JsonConvert.SerializeObject(model);
}

使用 Provider,只需要将 Provider 绑定到属性字段即可。例如:

[Provider(typeof(JsonProvider<NameModel>))]
public NameModel NameModel { get; set; }

测试例子:

using (var context = ApplicationDbContext.UseMySql())
{
    context.LS_Providers.Add(new LS_Provider
    {
        Password = "0416",          // BASE64 储存
        NameModel = new NameModel   // JSON 储存
        { 
            Name = "Jack",
            NickName = "zmjack",
        },
    });
    context.SaveChanges();
}

数据库记录:

e48574ac3e093350cbd048ec8afc5c7c.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值