前言

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创建数据库

  2. 新建类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;
    }
    }
  3. 新建用户上下文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>

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

    public class AddUserRequest
    {
    public string Name { get; set; } public uint Gender { get; set; } public DateTime BirthDay { get; set; }
    }
  5. 新建类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);
    }
    }
    }
  6. 修改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")
    });
  2. 修改Program.cs,使项目支持CodeFirst

    app.MigrateDbContext<UserDbContext>((context, services) =>
    {
    });

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

  3. 测试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
  2. 修改类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;)

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

    builder.Services.AddMasaDbContext<UserDbContext>(options =>
    {
    options.Builder = (_, dbContextOptionsBuilder) => dbContextOptionsBuilder.UseInMemoryDatabase("test");
    options.UseFilter();//启用数据过滤,完整写法:options.UseFilter(filterOptions => filterOptions.EnableSoftDelete = true);
    });
  4. 测试软删除是否成功

  • 修改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();
    }
    });
  2. 重新运行项目,重复执行验证软删除步骤,确保通过list方法访问不到数据

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

  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)等

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

    builder.Services.AddMasaDbContext<UserDbContext>(options => options.UseInMemoryDatabase().UseFilter());
  3. 修改appsettings.json,增加用户数据库连接字符串:

    {
    "ConnectionStrings": {
    "DefaultConnection": "test"//更换为指定的数据库连接字符串
    }
    }
  4. 修改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)
    {
    }
    }
  2. 修改配置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,值为数据库连接字符串
    });
    });
  2. 修改appsettings.json配置

    //  "ConnectionStrings": {
    // "User": "test"
    // },
  3. 调用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";
    }
  2. 新建类CustomizeDbConnectionStringProvider

    public class CustomizeDbConnectionStringProvider : IDbConnectionStringProvider
    {
    public List<MasaDbContextConfigurationOptions> DbContextOptionsList { get; } = new()
    {
    new MasaDbContextConfigurationOptions("test3")
    };
    }
  3. 修改Program.cs

    builder.Services.AddSingleton<IConnectionStringProvider,CustomizeConnectionStringProvider>();
    builder.Services.AddSingleton<IDbConnectionStringProvider,CustomizeDbConnectionStringProvider>();
  4. 调用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,欢迎联系我们

数据访问 - EntityFramework集成的更多相关文章

  1. Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问

    本篇内容还是建立在上一篇Java Web学习系列——Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Jar包 这 ...

  2. ABP官方文档翻译 9.1 EntityFramework集成

    EntityFramework集成 Nuget包 DbContext 仓储 默认仓储 自定义仓储 应用特定的基础仓储类 自定义仓储示例 仓储最佳实践 事务管理 数据存储 ABP可以使用ORM框架,它内 ...

  3. ABP文档 - EntityFramework 集成

    文档目录 本节内容: Nuget 包 DbContext 仓储 默认仓储 自定义仓储 特定的仓储基类 自定义仓储示例 仓储最佳实践 ABP可使用任何ORM框架,它已经内置了EntityFrame(以下 ...

  4. ABP理论学习之EntityFramework集成

    返回总目录 本篇目录 Nuget包 创建DbContext 仓储 仓储基类 实现仓储 自定义仓储方法 阅读其他 ABP可以使用任何ORM框架工作,并且已经内置了EntityFramework集成.这篇 ...

  5. 在 ASP.NET 中创建数据访问和业务逻辑层(转)

    .NET Framework 4 当在 ASP.NET 中处理数据时,可从使用通用软件模式中受益.其中一种模式是将数据访问代码与控制数据访问或提供其他业务规则的业务逻辑代码分开.在此模式中,这两个层均 ...

  6. 测试 ClownFish、CYQ、Entity Framework、Moon、MySoft、NHibernate、PDF、XCode数据访问组件性能

    下期预告: 由于很多园友反馈,有的组件不应该缺席.测试复杂度不够.测试还缺乏一定的公平. 因此考虑在下一个版本中,确保在更加公平的前提下进行更高复杂度的测试 . 同时将分为2组测试,纯SQL组件及纯O ...

  7. Yii的学习(2)--数据访问对象 (DAO)

    摘自Yii官网:http://www.yiiframework.com/doc/guide/1.1/zh_cn/database.dao Yii提供了强大的数据库编程支持.Yii数据访问对象(DAO) ...

  8. 数据访问层DAL(数据库访问抽象类DataProvider)

    晒晒数据访问层DAL,看看你的项目数据访问层使用的是什么形式,数据访问性能比较 采用什么样的数据访问形式是软件编码很重要的一个环节,良好的数据访问形式不仅能够提搞代码的执行效率,协作能力,更重要的是对 ...

  9. 数据访问模式之Repository模式

    数据访问模式之Repository模式   数据访问层无非就是对数据进行增删改查,其中增.删.改等我们可以抽象出来写一个公共的接口或抽象类来定义这些方法,并采用一个基类实现这些方法,这样该基类派生的子 ...

随机推荐

  1. 面试突击41:notify是随机唤醒吗?

    做 Java 开发的小伙伴,对 wait 方法和 notify 方法应该都比较熟悉,这两个方法在线程通讯中使用的频率非常高,但对于 notify 方法的唤醒顺序,有很多小伙伴的理解都是错误的,有很多人 ...

  2. spring boot的配置文件

    1.SpringBootApplication是标志启动类,启动后可以把这个类所在的包资源发布到服务器,不用再启动tomcat 2.利用spring boot工程可以和以前一样直接在Controlll ...

  3. XCTF练习题---MISC---倒立屋

    XCTF练习题---MISC---倒立屋 flag:flag{9102_cCsI} 解题步骤: 1.观察题目,下载附件 2.打开发现是个倒立的屋子,并没有发现啥东西,拿StegSolve看看 3.查了 ...

  4. spring盒springMVC整合父子容器问题:整合Spring时Service层为什么不做全局包扫描详解

    整合Spring时Service层为什么不做全局包扫描详解 一.Spring和SpringMVC的父子容器关系 1.讲问题之前要先明白一个关系 一般来说,我们在整合Spring和SpringMVC这两 ...

  5. [题解] 51 nod 1340 地铁环线

    不难看出这是一道差分约束的题目. 但是如果想按照通常的题目那样去建边的话,就会发现这句话--相邻两站的距离至少是1公里--建边后就直接让整个题出现了负环(默认是按求最短路建边),没法做了. 这时我们就 ...

  6. 面试官问:浏览器输入 URL 回车之后发生了什么?

    一个执着于技术的公众号 前言 这个问题已经是老生常谈了,更是经常被作为面试的压轴题出现,网上也有很多文章,但最近闲的无聊,然后就自己做了一篇笔记,感觉比之前理解更透彻了. 注意:本文的步骤是建立在,请 ...

  7. 关于background-*的一些属性

    1.盒模型 盒模型从外到内一次为:margin-box.border-box.padding-box.content-box. 2.一些属性设置的相对位置 ⑴background-position的属 ...

  8. Linux 设置开机自启动脚本(ES、MySQL、Nacos、Nginx)

    /etc/rc.d/init.d 中文件会在 Linux 系统各项服务都启动完毕之后再被运行 cd /etc/rc.d/init.d:新建xxx.sh文件. chmod +x xxx.sh,赋予可执行 ...

  9. UNIAPP实现PDA扫码

    目前我接触到了两种方法,以扫码pda安卓采集器(可以直接理解为手机上有个激光扫码)的设置划分. 1.扫描设置 --> 键盘方式输出(键盘类型:物理键盘),注意设置要看具体的型号: 2.扫码设置 ...

  10. ReentrantLock可重入、可打断、Condition原理剖析

    本文紧接上文的AQS源码,如果对于ReentrantLock没有基础可以先阅读我的上一篇文章学习ReentrantLock的源码 ReentrantLock锁重入原理 重入加锁其实就是将AQS的sta ...