章台客 发表于 2023-5-24 12:21:20

Entity Framework的最佳实践一

Entity Framework (EF) Core 是轻量化、可扩展、开源和跨平台版的常用 Entity Framework 数据访问技术。EF Core 可用作对象关系映射程序 (O/RM) 

创建DbContext 对象

DbContext的生存期

DbContext 的生存期从创建实例时开始,并在释放实例时结束。DbContext生成


[*]通过依赖关系
为每个请求创建一个 ApplicationDbContext 实例,并传递给控制器,以在请求结束后释放前执行工作单元public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddDbContext<ApplicationDbContext>(
      options => options.UseSqlServer("name=ConnectionStrings:DefaultConnection"));
}
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
      : base(options)
    {
    }
}
public class MyController
{
    private readonly ApplicationDbContext _context;
    public MyController(ApplicationDbContext context)
    {
      _context = context;
    }
}

[*]通过关键字 “new”
 public class ApplicationDbContext : DbContext
{
    private readonly string _connectionString;
    public ApplicationDbContext(string connectionString)
    {
      _connectionString = connectionString;
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
      optionsBuilder.UseSqlServer(_connectionString);
    }
}
//或者
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
      : base(options)
    {
    }
}
var contextOptions = new DbContextOptionsBuilder<ApplicationDbContext>()
    .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test")
    .Options;

using var context = new ApplicationDbContext(contextOptions); 

DBContext的属性

DbContextOptionsBuilder

所有DBContext配置的起始点都是 DbContextOptionsBuilder。 可以通过三种方式获取此生成器:

[*]在 AddDbContext 和相关方法中
[*]在 OnConfiguring 中
[*]使用 new 显式构造
DbContextOptions

允许多个具体子类使用其不同的泛型 DbContextOptions 的实例初始化DBContext public sealed class ApplicationDbContext1 : ApplicationDbContextBase
{
    public ApplicationDbContext1(DbContextOptions<ApplicationDbContext1> contextOptions)
      : base(contextOptions)
    {
    }
}
public sealed class ApplicationDbContext2 : ApplicationDbContextBase
{
    public ApplicationDbContext2(DbContextOptions<ApplicationDbContext2> contextOptions)
      : base(contextOptions)
    {
    }
}
   protected ApplicationDbContext(DbContextOptions contextOptions)
      : base(contextOptions)
    {
    } 

DBContext的两个关键方法

OnConfiguring配置方法

DBContext的配置入口    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
      //配置数据库提供程序,还有其他数据库配置如下图:
      optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test");
      //日志记录配置,通过在控制台输出
      optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information).EnableSensitiveDataLogging();
      //关于其他DBContext配置,参看下图
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
      base.OnModelCreating(modelBuilder, typeof(BaseEntity));
    }关于其他数据库提供程序

数据库系统配置示例NuGet 程序包SQL Server 或 Azure SQL.UseSqlServer(connectionString)Microsoft.EntityFrameworkCore.SqlServerAzure Cosmos DB.UseCosmos(connectionString, databaseName)Microsoft.EntityFrameworkCore.CosmosSQLite.UseSqlite(connectionString)Microsoft.EntityFrameworkCore.SqliteEF Core 内存中数据库.UseInMemoryDatabase(databaseName)Microsoft.EntityFrameworkCore.InMemoryPostgreSQL*.UseNpgsql(connectionString)Npgsql.EntityFrameworkCore.PostgreSQLMySQL/MariaDB*.UseMySql(connectionString)Pomelo.EntityFrameworkCore.MySqlOracle*.UseOracle(connectionString)Oracle.EntityFrameworkCore关于DbContextOptionsBuilder 的更多配置

DbContextOptionsBuilder 方法作用了解更多UseQueryTrackingBehavior设置查询的默认跟踪行为查询跟踪行为LogTo获取 EF Core 日志的一种简单方法日志记录、事件和诊断UseLoggerFactory注册Microsoft.Extensions.Logging工厂日志记录、事件和诊断EnableSensitiveDataLogging在异常和日志记录中包括应用程序数据日志记录、事件和诊断EnableDetailedErrors更详细的查询错误(以性能为代价)日志记录、事件和诊断ConfigureWarnings忽略或引发警告和其他事件日志记录、事件和诊断AddInterceptors注册 EF Core 侦听器日志记录、事件和诊断UseLazyLoadingProxies使用动态代理进行延迟加载延迟加载UseChangeTrackingProxies使用动态代理进行更改跟踪即将推出... 

OnModelCreating配置方法

实体的配置入口方法 
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {

      modelBuilder.Entity<AuditEntry>();
    } 

使用 fluent API 配置模型替代OnModelCreating

关于实体的配置,还可使用Fluent api 可在上下文中替代 OnModelCreating 方法,并使用 Fluent API 来配置模型。 此配置方法最为有效,并可在不修改实体类的情况下指定配置。 Fluent API 配置具有最高优先级,并将替代约定和数据注释。 配置按调用方法的顺序应用,如果存在任何冲突,最新调用将替代以前指定的配置。查看代码 modelBuilder.Entity<Blog>()
            .Property(b => b.Url)
            .IsRequired();//代替修改实体
还有这种等等            

public class BlogMetadata
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Ignore<BlogMetadata>();


DBContext的结构

模型

模型由实体类和表示数据库会话的上下文对象构成。 上下文对象允许查询并保存数据     public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
      optionsBuilder.UseSqlServer(
            @"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True");
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
    public int Rating { get; set; }
    public List<Post> Posts { get; set; }


实体

在上下文中包含一种类型的 DbSet 意味着它包含在 EF Core 的模型中,或者在OnModelCreating 指定的;我们通常将此类类型称为实体加入实体的三种方式


[*]在上下文的 DbSet 属性中公开。
[*]通过实体 Blog.Posts 的导航属性发现的。
[*]在 OnModelCreating 中指定的。
 internal class MyContext : DbContext
{

    public DbSet<Blog> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {

      modelBuilder.Entity<AuditEntry>();
    }
}

public class Blog
{
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{

    public string Content { get; set; }



实体的属性约束

关于属性的约束,查看一下链接 实体属性 - EF Core | Microsoft Learn以下列出常用等等  指定数据库列映射,数据库列与实体列不一致   描述  

实体状态变化规则

DBContext上下文为跟踪状态时,实体变化如下; 

EntityState的5个状态解释:

  成员名称说明Detached对象存在,但没有被跟踪。 在创建实体之后、但将其添加到对象上下文之前,该实体处于此状态。 An entity is also in this state after it has been removed from the context by calling the Detach method or if it is loaded by using a NoTrackingMergeOption. 没有 ObjectStateEntry 实例与状态为 Detached 的对象关联。Unchanged自对象附加到上下文中后,或自上次调用 SaveChanges 方法后,此对象尚未经过修改。Added对象为新对象,并且已添加到对象上下文,但尚未调用 SaveChanges 方法。 在保存更改后,对象状态将更改为 Unchanged。 状态为 Added 的对象在 ObjectStateEntry 中没有原始值。Modified对象上的一个标量属性已更改,但尚未调用 SaveChanges 方法。 在不带更改跟踪代理的 POCO 实体中,调用 DetectChanges 方法时,已修改属性的状态将更改为 Modified。 在保存更改后,对象状态将更改为 Unchanged。Deleted删除状态 

手动设置实体状态

  _mIPODataDBContext.Entry(t_TaskOrderFiles).Property(x => x.Url).IsModified = true;
_mIPODataDBContext.SaveChanges(); 

DBContext的查询方式

跟踪和不跟踪查询(AsNoTracking)

 //跟踪
var blog = context.Blogs.SingleOrDefault(b => b.BlogId == 1);
blog.Rating = 5;
context.SaveChanges();
//不跟踪
var blogs = context.Blogs
    .AsNoTracking()
    .ToList();
//在上下文实例级别取消跟踪
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; 

导航查询(Include,ThenInclude)

 //同级Include,子级,更深级别的关联 ThenInclude
var blogs = context.Blogs
      .Include(blog => blog.Posts)
      .ThenInclude(post => post.Author)
      .ToList(); 

Inner Join查询

通过linq表达式

 var query = from photo in context.Set<PersonPhoto>()
            join person in context.Set<Person>()
                on new { Id = (int?)photo.PersonPhotoId, photo.Caption }
                equals new { Id = person.PhotoId, Caption = "SN" }
            where b.ProjectOrderId == Guid.Parse(proIdParam.Value) && p.IsDel == false
            select new { person, photo };
            
SELECT ., ., ., ., ., .
FROM AS
INNER JOIN AS ON (. = . AND (. = N'SN')) 

通过lamada表达式

 var query = from b in context.Set<Blog>()
            from p in context.Set<Post>().Where(p => b.BlogId == p.BlogId)
            select new { b, p };
            
SELECT ., ., ., ., ., ., ., ., ., .
FROM AS
INNER JOIN AS ON . = . 

Left Join查询

lamada表达式

 var query = from b in context.Set<Blog>()
            join p in context.Set<Post>()
                on b.BlogId equals p.BlogId into grouping
            from p in grouping.DefaultIfEmpty()
            select new { b, p }; 

linq表达式

 var query2 = from b in context.Set<Blog>()
             from p in context.Set<Post>().Where(p => b.BlogId == p.BlogId).DefaultIfEmpty()
             select new { b, p };

SELECT ., ., ., ., ., ., ., ., ., .
FROM AS
LEFT JOIN AS ON . = . 

GroupJoin查询

 var query = from b in context.Set<Blog>()
            join p in context.Set<Post>()
                on b.BlogId equals p.BlogId into grouping
            select new { b, Posts = grouping.Where(p => p.Content.Contains("EF")).ToList() }; 

GroupBy查询

 var query = from p in context.Set<Post>()
            group p by p.AuthorId
            into g
            where g.Count() > 0
            orderby g.Key
            select new { g.Key, Count = g.Count() };
            
SELECT . AS , COUNT(*) AS
FROM AS
GROUP BY .
HAVING COUNT(*) > 0
ORDER BY .    支持的其他聚合运算符.NETSQLAverage(x => x.Property)AVG(Property)Count()COUNT(*)LongCount()COUNT(*)Max(x => x.Property)MAX(Property)Min(x => x.Property)MIN(Property)Sum(x => x.Property)SUM(Property) 

纯SQL查询

  var rowsModified = context.Database.ExecuteSql($"UPDATE SET = NULL");

var overAverageIds = context.Database
    .SqlQuery<int>($"SELECT AS FROM ")
    .Include(b => b.Posts)
    .Where(id => id > context.Blogs.Average(b => b.BlogId))
    .ToList(); 
来源:https://www.cnblogs.com/workcn/archive/2023/05/24/17427415.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Entity Framework的最佳实践一