5. Data Access - EntityFramework Integration

foreword

MasaProvides EntityFrameworkdata integration based on data, and provides functions of data filtering and soft deletion. Below we will introduce how to use it?

Getting Started with MasaDbContext

  1. Create a new ASP.NET Core empty project Assignment.MasaEntityFrameworkand install Masa.Contrib.Data.EntityFrameworkCore, Swashbuckle.AspNetCore, Microsoft.EntityFrameworkCore.InMemory,Microsoft.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
    

    The installation Swashbuckle.AspNetCoreis for the convenience Swaggerof operating the service installation Microsoft.EntityFrameworkCore.InMemoryis for the convenience, so use the in-memory database, if you need to use other databases, please install the corresponding package by yourself The installation Microsoft.EntityFrameworkCore.Toolsis to use CodeFirst to create a database

  2. new classUser

    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. New user contextUserDbContext.cs

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

    UserDbContextChange to inheritance MasaDbContext, and add a constructor with a parameter, the parameter type is MasaDbContextOptionsWhen there are multiple DbContexts in the project, it needs to be changed to inheritance MasaDbContext<TDbContext>, and the parameter type of the constructor is changed toMasaDbContext<TDbContext>

  4. Create a new class AddUserRequestas a parameter to add a user

    public class AddUserRequest
    {
        public string Name { get; set; }
    
        public uint Gender { get; set; }
    
        public DateTime BirthDay { get; set; }
    }
    
  5. New class HostExtensionsfor migrating database (using 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. Modify Program.cs, add Swaggersupport

    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();
    
    var app = builder.Build();
    
    app.UseSwagger();
    app.UseSwaggerUI();
    

No need Swaggerto add, use Swagger just to test the calling service, Postmanor other Http tools can also be used

  1. Modify Program.cs, add user context (emphasis)

    builder.Services.AddMasaDbContext<UserDbContext>(options => 
    {
      options.Builder = (_, dbContextOptionsBuilder) => dbContextOptionsBuilder.UseInMemoryDatabase("test")
    });
    
  2. Modified Program.csto make the project support CodeFirst

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

    CodeFirst is not required, and it is not necessary to add a database that does not support code generation

  3. test MasaDbContext, modifyProgram.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();
    });
    

    Run the project by yourself add, create a new user after execution, and then execute listto get more than one user data, which proves that the MasaDbContextuse is correct

How to use soft delete

  1. select Assignment.MasaEntityFrameworkand installMasa.Contrib.Data.Contracts.EF

    dotnet add package Masa.Contrib.Data.Contracts.EF --version 0.4.0-rc.4
    
  2. Modify the class Userand implement ISoftDelete, the code is changed to:

    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;
        }
    }
    

    Add implementation ISoftDelete, and IsDeletedadd set support for properties (can be private set;)

  3. Modify Program.csand enable data filtering

    builder.Services.AddMasaDbContext<UserDbContext>(options =>
    {
        options.Builder = (_, dbContextOptionsBuilder) => dbContextOptionsBuilder.UseInMemoryDatabase("test");
        options.UseFilter();//启用数据过滤,完整写法:options.UseFilter(filterOptions => filterOptions.EnableSoftDelete = true);
    });
    
  4. Test if the soft delete was successful

  • Modify Program.cs, add delete method

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

Finally, first call the addmethod to create a user, then call listthe method to obtain a list of all users, and retrieve any id information, then call the deletemethod to delete the user, and finally call listthe method to check whether the retrieved id exists, so as to verify the software. Whether the deletion is valid.

How to temporarily disable soft delete filtering

In the default query, the data that has been marked deleted will be filtered and no longer queried, but there are also some scenarios where all data needs to be queried, in which case data filtering is requiredIDataFilter

  1. Added Allmethod for querying all data (including data marked for deletion)

    app.MapGet("/all", (UserDbContext dbContext, [FromServices] IDataFilter dataFilter) =>
    {
        //通过DI获取到IDataFilter,并调用其Disable方法可临时禁用ISoftDelete条件过滤
        using (dataFilter.Disable<ISoftDelete>())
        {
            return dbContext.Set<User>().ToList();
        }
    });
    
  2. Rerun the project and repeat the verify soft delete steps to ensure that the listdata is not accessible through the method

    The reason for running the verification soft delete step repeatedly is that this example uses an in-memory database. After the project is stopped, all data will be emptied. The re-execution is to ensure that the data exists and is only marked for deletion.

  3. Execute the allmethod, get all the data, and check whether the user data corresponding to the id exists

Get database connection string from configuration file

  1. Select the project Assignment.MasaEntityFrameworkand installMasa.Contrib.Data.EntityFrameworkCore.InMemory

    dotnet add package Masa.Contrib.Data.EntityFrameworkCore.InMemory --version 0.4.0-rc.4
    

    Install the corresponding database package as needed, such as: Masa.Contrib.Data.EntityFrameworkCore.SqlServer(SqlServer), Masa.Contrib.Data.EntityFrameworkCore.Pomelo.MySql(MySql provided by Pomelo), Masa.Contrib.Data.EntityFrameworkCore.Oracle(Oracle), etc.

  2. Modify Program.cs, adjust the add user context configuration to:

    builder.Services.AddMasaDbContext<UserDbContext>(options => options.UseInMemoryDatabase().UseFilter());
    
  3. Modify appsettings.json, increase the user database connection string:

    {
      "ConnectionStrings": {
        "DefaultConnection": "test"//更换为指定的数据库连接字符串
      }
    }
    
  4. Modify Program.cs, add databasea method, verify that the current database istest

    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 "";
    });
    

Last visit http://localhost:5002/databaseto verify whether the current database name is the same as the modified database nameVerify the database is test

common problem

  • How to change the default read configuration node?
  1. Modify the user context UserDbContextand add ConnectionStringNamefeatures:

    [ConnectionStringName("User")]//自定义节点名
    public class UserDbContext : MasaDbContext
    {
        public DbSet<User> User { get; set; }
    
        public UserDbContext(MasaDbContextOptions options) : base(options)
        {
        }
    }
    
  2. Change settingappsettings.json

    {
      "ConnectionStrings": {
        "User": "test"//改为从User节点读取数据库连接字符串
      }
    }
    
  • Is it supported to get the database connection string from somewhere other than from the config file?

There are currently two ways to change the database connection string.

Method 1: Modify Program.csand delete appsettings.jsonthe configuration of the database connection string

  1. ReviseProgram.cs

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

    //  "ConnectionStrings": {
    //    "User": "test"
    //  },
    
  3. Call databasethe method to verify whether the current database istest2

Verify that the database is test2

Method 2: Override the implementation of IConnectionStringProvidersum IDbConnectionStringProviderand add to DI

  1. new classCustomizeConnectionStringProvider

    public class CustomizeConnectionStringProvider : IConnectionStringProvider
    {
        public Task<string> GetConnectionStringAsync(string name = "DefaultConnection") => Task.FromResult    (GetConnectionString(name));
    
        public string GetConnectionString(string name = "DefaultConnection") => "test3";
    }
    
  2. new classCustomizeDbConnectionStringProvider

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

    builder.Services.AddSingleton<IConnectionStringProvider,CustomizeConnectionStringProvider>();
    builder.Services.AddSingleton<IDbConnectionStringProvider,CustomizeDbConnectionStringProvider>();
    
  4. Call databasethe method to verify whether the current database istest3 Verify that the database is test3

Summarize

This article mainly explains the MasaDbContextbasic usage and how to use soft delete and data filtering. In the next article, we will explain MasaDbContexthow to implement soft delete and data filtering, and how to use the database without specifying the database link character mentioned in this article. How is the string time implemented?

Source code of this chapter

Assignment05

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

open source address

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

If you are interested in our MASA Framework, whether it is code contribution, use, issue, please contact us

16373211753064.png

{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/5447363/blog/5549631