写点什么

5. 数据访问 - EntityFramework 集成

  • 2022 年 7 月 05 日
  • 本文字数:5204 字

    阅读完需:约 17 分钟

前言

Masa提供了基于EntityFramework的数据集成,并提供了数据过滤与软删除的功能,下面我们将介绍如何使用它?


MasaDbContext 入门


  1. 新建 ASP.NET Core 空项目Assignment.MasaEntityFramework,并安装Masa.Contrib.Data.EntityFrameworkCoreSwashbuckle.AspNetCoreMicrosoft.EntityFrameworkCore.InMemoryMicrosoft.EntityFrameworkCore.Tools


    dotnet add package Masa.Contrib.Data.EntityFrameworkCore --version 0.4.0-rc.4    dotnet add package Swashbuckle.AspNetCore --version 6.2.3    dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 6.0.5    dotnet add package Microsoft.EntityFrameworkCore.Tools --version 6.0.5
复制代码


> 安装`Swashbuckle.AspNetCore`是为了方便通过`Swagger`来操作服务> 安装`Microsoft.EntityFrameworkCore.InMemory`是为了方便,因此使用内存数据库,如果需要使用其他数据库,请自行安装对应的包> 安装`Microsoft.EntityFrameworkCore.Tools`是为了使用CodeFirst创建数据库
复制代码


  1. 新建类User


    public class User    {        public int Id { get; set; }            public string Name { get; set; }            public uint Gender { get; set; }            public DateTime BirthDay { get; set; }            public DateTime CreationTime { get; set; }            public User()        {            this.CreationTime = DateTime.Now;        }    }
复制代码


  1. 新建用户上下文UserDbContext.cs


    public class UserDbContext : MasaDbContext    {        public DbSet<User> User { get; set; }            public UserDbContext(MasaDbContextOptions options) : base(options)        {        }    }
复制代码


> `UserDbContext`改为继承`MasaDbContext`, 并新增一个参数的构造函数,参数类型为`MasaDbContextOptions`> 当项目中存在多个DbContext时,需要改为继承`MasaDbContext<TDbContext>`,构造函数参数类型改为`MasaDbContext<TDbContext>`
复制代码


  1. 新建类AddUserRequest作为添加用户的参数


    public class AddUserRequest    {        public string Name { get; set; }            public uint Gender { get; set; }            public DateTime BirthDay { get; set; }    }
复制代码


  1. 新建类HostExtensions用于迁移数据库(使用 CodeFirst)


    public static class HostExtensions    {        public static void MigrateDbContext<TContext>(            this IHost host, Action<TContext, IServiceProvider> seeder) where TContext : DbContext        {            using (var scope = host.Services.CreateScope())            {                var services = scope.ServiceProvider;                var context = services.GetRequiredService<TContext>();                context.Database.EnsureCreated();                seeder(context, services);            }        }    }
复制代码


  1. 修改Program.cs,新增Swagger支持


    builder.Services.AddEndpointsApiExplorer();    builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseSwagger(); app.UseSwaggerUI();
复制代码


不需要Swagger可不添加,使用 Swagger 仅仅是为了测试调用服务,使用Postman或其他的 Http 工具也可以


  1. 修改Program.cs,添加用户上下文(重点)


    builder.Services.AddMasaDbContext<UserDbContext>(options =>     {      options.Builder = (_, dbContextOptionsBuilder) => dbContextOptionsBuilder.UseInMemoryDatabase("test")    });
复制代码


  1. 修改Program.cs,使项目支持 CodeFirst


    app.MigrateDbContext<UserDbContext>((context, services) =>    {    });
复制代码


> 不需要CodeFirst,不支持代码生成数据库可不添加
复制代码


  1. 测试MasaDbContext,修改Program.cs


    app.MapPost("/add", (UserDbContext dbContext, [FromBody] AddUserRequest request) =>    {        dbContext.Set<User>().Add(new User()        {            Name = request.Name,            Gender = request.Gender,            BirthDay = request.BirthDay        });        dbContext.SaveChanges();    });        app.MapGet("/list", (UserDbContext dbContext) =>    {        return dbContext.Set<User>().ToList();    });
复制代码


> 自行运行项目,执行`add`后创建一个新的用户,之后执行`list`得到一个以上的用户数据,则证明`MasaDbContext`使用无误
复制代码

如何使用软删除

  1. 选中Assignment.MasaEntityFramework并安装Masa.Contrib.Data.Contracts.EF


    dotnet add package Masa.Contrib.Data.Contracts.EF --version 0.4.0-rc.4
复制代码


  1. 修改类User,并实现ISoftDelete,代码改为:


    public class User : ISoftDelete//重点:改为实现ISoftDelete    {        public int Id { get; set; }            public string Name { get; set; }            public uint Gender { get; set; }            public DateTime BirthDay { get; set; }            public DateTime CreationTime { get; set; }            public bool IsDeleted { get; private set; }            public User()        {            this.CreationTime = DateTime.Now;        }    }
复制代码


> 增加实现`ISoftDelete`,并为`IsDeleted`属性添加set支持(可以是private set;)
复制代码


  1. 修改Program.cs,并启用数据过滤


    builder.Services.AddMasaDbContext<UserDbContext>(options =>    {        options.Builder = (_, dbContextOptionsBuilder) => dbContextOptionsBuilder.UseInMemoryDatabase("test");        options.UseFilter();//启用数据过滤,完整写法:options.UseFilter(filterOptions => filterOptions.EnableSoftDelete = true);    });
复制代码


  1. 测试软删除是否成功


  • 修改Program.cs,新增删除方法


    app.MapDelete("/delete", (UserDbContext dbContext, int id) =>    {        var user = dbContext.Set<User>().First(u => u.Id == id);        dbContext.Set<User>().Remove(user);        dbContext.SaveChanges();    });
复制代码


最后,先调用add方法创建用户后,之后再调用list方法获取所有的用户列表,并取出任意一条 id 信息,然后再调用delete方法删除用户,最后再调用list方法,查看取出的 id 是否存在,以此来验证软删除是否有效。

如何临时禁用软删除过滤

默认查询中会将标记已经被删除的数据过滤不再进行查询,但也有一些场景需要查询所有的数据,此时就需要用到数据过滤IDataFilter


  1. 新增All方法用于查询所有的数据(包含标记已经删除的数据)


    app.MapGet("/all", (UserDbContext dbContext, [FromServices] IDataFilter dataFilter) =>    {        //通过DI获取到IDataFilter,并调用其Disable方法可临时禁用ISoftDelete条件过滤        using (dataFilter.Disable<ISoftDelete>())        {            return dbContext.Set<User>().ToList();        }    });
复制代码


  1. 重新运行项目,重复执行验证软删除步骤,确保通过list方法访问不到数据

  2. 重复运行验证软删除步骤的原因在于本示例使用的是内存数据库,项目停止后,所有数据都会被清空,重新执行是为了确保数据存在,仅被标记为删除

  3. 执行all方法,获取所有的数据,查看 id 所对应的用户数据是否存在

从配置文件中获取数据库连接字符串

  1. 选中项目Assignment.MasaEntityFramework,并安装Masa.Contrib.Data.EntityFrameworkCore.InMemory


    dotnet add package Masa.Contrib.Data.EntityFrameworkCore.InMemory --version 0.4.0-rc.4
复制代码


> 根据需要安装对应数据库包即可,如:`Masa.Contrib.Data.EntityFrameworkCore.SqlServer` (SqlServer)、`Masa.Contrib.Data.EntityFrameworkCore.Pomelo.MySql` (Pomelo提供的MySql)、`Masa.Contrib.Data.EntityFrameworkCore.Oracle` (Oracle)等
复制代码


  1. 修改Program.cs,调整添加用户上下文配置为:


    builder.Services.AddMasaDbContext<UserDbContext>(options => options.UseInMemoryDatabase().UseFilter());
复制代码


  1. 修改appsettings.json,增加用户数据库连接字符串:


    {      "ConnectionStrings": {        "DefaultConnection": "test"//更换为指定的数据库连接字符串      }    }
复制代码


  1. 修改Program.cs,新增database方法,验证当前数据库是test


    app.MapGet("/database", (UserDbContext dbContext) =>    {        var field = typeof(MasaDbContext).GetField("Options", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic)!;        var masaDbContextOptions = field.GetValue(dbContext) as MasaDbContextOptions;        foreach (var dbContextOptionsExtension in masaDbContextOptions!.Extensions)        {            if (dbContextOptionsExtension is InMemoryOptionsExtension memoryOptionsExtension)            {                return memoryOptionsExtension.StoreName;            }        }            return "";    });
复制代码


最后访问http://localhost:5002/database,验证当前的数据库名称与修改后的数据库名称是否一致


常见问题

  • 如何更改默认读取的配置节点?


  1. 修改用户上下文UserDbContext并增加ConnectionStringName特性:


    [ConnectionStringName("User")]//自定义节点名    public class UserDbContext : MasaDbContext    {        public DbSet<User> User { get; set; }            public UserDbContext(MasaDbContextOptions options) : base(options)        {        }    }
复制代码


  1. 修改配置appsettings.json


    {      "ConnectionStrings": {        "User": "test"//改为从User节点读取数据库连接字符串      }    }
复制代码


  • 除了从配置文件中获取,还支持从其他地方获取数据库连接字符串吗?


目前有两种办法可以更改数据库连接字符串。


方法 1: 修改Program.cs,并删除appsettings.json数据库连接字符串的配置


  1. 修改Program.cs


    builder.Services.Configure<MasaDbConnectionOptions>(option =>    {        option.ConnectionStrings = new ConnectionStrings(new List<KeyValuePair<string, string>>()        {            new("User", "test2")//其中键为节点名,与ConnectionStringName特性的Name值保持一致即可,如果未指定ConnectionStringName,则应该为DefaultConnection,值为数据库连接字符串        });    });
复制代码


  1. 修改appsettings.json配置


    //  "ConnectionStrings": {    //    "User": "test"    //  },
复制代码


  1. 调用database方法,验证当前数据库是否为test2



方法 2: 重写IConnectionStringProviderIDbConnectionStringProvider的实现并添加到 DI 中


  1. 新建类CustomizeConnectionStringProvider


    public class CustomizeConnectionStringProvider : IConnectionStringProvider    {        public Task<string> GetConnectionStringAsync(string name = "DefaultConnection") => Task.FromResult    (GetConnectionString(name));            public string GetConnectionString(string name = "DefaultConnection") => "test3";    }
复制代码


  1. 新建类CustomizeDbConnectionStringProvider


    public class CustomizeDbConnectionStringProvider : IDbConnectionStringProvider    {        public List<MasaDbContextConfigurationOptions> DbContextOptionsList { get; } = new()        {            new MasaDbContextConfigurationOptions("test3")        };    }
复制代码


  1. 修改Program.cs


    builder.Services.AddSingleton<IConnectionStringProvider,CustomizeConnectionStringProvider>();    builder.Services.AddSingleton<IDbConnectionStringProvider,CustomizeDbConnectionStringProvider>();
复制代码


  1. 调用database方法,验证当前数据库是否为test3

总结

本篇文章主要讲解了MasaDbContext的基本用法以及软删除、数据过滤如何使用,下篇文章我们会讲解一下MasaDbContext是如何实现软删除、数据过滤的,以及本篇文章中提到使用数据库时不指定数据库链接字符串时如何实现的

本章源码

Assignment05


https://github.com/zhenlei520/MasaFramework.Practice

开源地址

MASA.BuildingBlocks:https://github.com/masastack/MASA.BuildingBlocks


MASA.Contrib:https://github.com/masastack/MASA.Contrib


MASA.Utils:https://github.com/masastack/MASA.Utils


MASA.EShop:https://github.com/masalabs/MASA.EShop


MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor


如果你对我们的 MASA Framework 感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们



发布于: 刚刚阅读数: 3
用户头像

还未添加个人签名 2021.10.26 加入

还未添加个人简介

评论

发布
暂无评论
5. 数据访问 - EntityFramework集成_C#_MASA技术团队_InfoQ写作社区