首页 > 其他分享 >Entity Framework的最佳实践一

Entity Framework的最佳实践一

时间:2023-05-25 10:24:43浏览次数:38  
标签:最佳 class public Framework context var new Entity BlogId

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.SqlServer
Azure Cosmos DB .UseCosmos(connectionString, databaseName) Microsoft.EntityFrameworkCore.Cosmos
SQLite .UseSqlite(connectionString) Microsoft.EntityFrameworkCore.Sqlite
EF Core 内存中数据库 .UseInMemoryDatabase(databaseName) Microsoft.EntityFrameworkCore.InMemory
PostgreSQL* .UseNpgsql(connectionString) Npgsql.EntityFrameworkCore.PostgreSQL
MySQL/MariaDB* .UseMySql(connectionString) Pomelo.EntityFrameworkCore.MySql
Oracle* .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();  //代替修改实体
还有这种等等            
[NotMapped]
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 以下列出常用
等等  
[NotMapped]  
[Column("blog_id")] 指定数据库列映射,数据库列与实体列不一致
[Column(TypeName = "varchar(200)")]  
[MaxLength(500)]  
[Required]  
[Comment("The URL of the blog")] 描述
[Column(Order = 2)]  

 

实体状态变化规则

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

 

EntityState的5个状态解释:

  0  
成员名称 说明
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 [p].[PersonId], [p].[Name], [p].[PhotoId], [p0].[PersonPhotoId], [p0].[Caption], [p0].[Photo]
FROM [PersonPhoto] AS [p0]
INNER JOIN [Person] AS [p] ON ([p0].[PersonPhotoId] = [p].[PhotoId] AND ([p0].[Caption] = 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 [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], [p].[PostId], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Rating], [p].[Title]
FROM [Blogs] AS [b]
INNER JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]

 

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 [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], [p].[PostId], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Rating], [p].[Title]
FROM [Blogs] AS [b]
LEFT JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]

 

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 [p].[AuthorId] AS [Key], COUNT(*) AS [Count]
FROM [Posts] AS [p]
GROUP BY [p].[AuthorId]
HAVING COUNT(*) > 0
ORDER BY [p].[AuthorId]    
支持的其他聚合运算符
.NET SQL
Average(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 [Blogs] SET [Url] = NULL");
 
 var overAverageIds = context.Database
    .SqlQuery<int>($"SELECT [BlogId] AS [Value] FROM [Blogs]")
    .Include(b => b.Posts)
    .Where(id => id > context.Blogs.Average(b => b.BlogId))
    .ToList();
 

标签:最佳,class,public,Framework,context,var,new,Entity,BlogId
From: https://www.cnblogs.com/yanglang/p/17430347.html

相关文章

  • JPA通用策略生成器(@GeneratedValue 四种标准用法为TABLE, SEQUENCE, IDENTITY, AUTO)
    JPA通用策略生成器查看JPA的源码可知:packagejavax.persistence;/***Definesthetypesofprimarykeygenerationstrategies.**@seeGeneratedValue**@sinceJavaPersistence1.0*/publicenumGenerationType{/***Indicatesthatthepers......
  • springboot项目启动报错java.lang.NoSuchMethodError: org.springframework.boot.buil
    产生此问题的原因是由于springboot版本兼容性导致的:java.lang.NoSuchMethodError:org.springframework.boot.builder.SpringApplicationBuilder.<init>([Ljava/lang/Object;)V2019-08-2918:04:54.089ERROR[restartedMain][SpringApplication.java:842]-Applicationrunfail......
  • Entity Framework的最佳实践一
    EntityFramework(EF)Core是轻量化、可扩展、开源和跨平台版的常用EntityFramework数据访问技术。EFCore可用作对象关系映射程序(O/RM) 创建DbContext 对象DbContext的生存期DbContext 的生存期从创建实例时开始,并在释放实例时结束。DbContext生成通过依......
  • ESM风潮下企业服务的最佳实践探讨
    甄知科技孵化于中国领先的IT咨询服务提供商-上海汉得信息技术股份有限公司,主打产品“燕千云”于2019年正式发布,持续迭代版本至今,燕千云作为企业数字化服务平台,燕千云的愿景和现状是为了帮助企业服务团队快速解决问题、优化服务流程、提高服务效率和服务质量,全面满足企业业务运营......
  • org.springframework.data.annotation.Transient 和 javax.persistence.Transient 的
    1、org.springframework.data.annotation.Transient 和 javax.persistence.Transient 都是用于标记一个属性不需要被持久化到数据库中的注解。它们的区别在于它们所处的框架和使用场景。org.springframework.data.annotation.Transient 是SpringDataJPA框架提供的注解,用......
  • 改进django rest framework中的token验证,并加入cache
        在用户验证方面用到token验证,这是一种安卓/iso/..手机客户端常用的,方便的验证方式。原理是客户端给我发一段字符串,这段字符串是用户在注册,登入的时候、服务器生成的,并关联到用户。保存到数据库,然后返回给客户端,客户端之后呢,就可以凭借这个字符串来确认“我是我,不是别人......
  • 利用 Django REST framework 编写 RESTful API
        自动生成符合RESTful规范的API支持OPTION、HEAD、POST、GET、PATCH、PUT、DELETE根据 Content-Type生成browserable的交互页面(自动为API生成非常友好的浏览器页面)非常细粒度的权限管理(可以细粒度到field级别)示意图安装$pipinstalldjangorestframew......
  • mac软件最佳资源下载站「macw」
    macw是一个专业的Mac苹果电脑软件下载网站。海量Mac软件,Mac教程技巧,壁纸,字体,模板,插件视频等资源集一身。有众多业界所推崇的主流软件,还有许多你不曾了解的小众精品软件。完美破解,人工测试,及时更新。更多详情:https://www.macw.com/?id=ODA2NCZfJjI3LjE4Ni4xMjUuMTE2......
  • 5个编写高效Makefile文件的最佳实践
    在软件开发过程中,Makefile是一个非常重要的工具,它可以帮助我们自动化构建、编译、测试和部署。然而,编写高效的Makefile文件并不是一件容易的事情。在本文中,我们将讨论如何编写高效的Makefile文件,以提高我们的开发效率和产品质量确定目标在编写Makefile文件之前,我们需要明确我......
  • 5个编写高效Makefile文件的最佳实践
    在软件开发过程中,Makefile是一个非常重要的工具,它可以帮助我们自动化构建、编译、测试和部署。然而,编写高效的Makefile文件并不是一件容易的事情。在本文中,我们将讨论如何编写高效的Makefile文件,以提高我们的开发效率和产品质量确定目标在编写Makefile文件之前,我们需要明确我......