翼度科技»论坛 编程开发 .net 查看内容

Entity Framework的最佳实践一

3

主题

3

帖子

9

积分

新手上路

Rank: 1

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

创建DbContext 对象

DbContext的生存期

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


  • 通过依赖关系
为每个请求创建一个 ApplicationDbContext 实例,并传递给控制器,以在请求结束后释放前执行工作单元
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3.     services.AddControllers();
  4.     services.AddDbContext<ApplicationDbContext>(
  5.         options => options.UseSqlServer("name=ConnectionStrings:DefaultConnection"));
  6. }
  7. public class ApplicationDbContext : DbContext
  8. {
  9.     public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
  10.         : base(options)
  11.     {
  12.     }
  13. }
  14. public class MyController
  15. {
  16.     private readonly ApplicationDbContext _context;
  17.     public MyController(ApplicationDbContext context)
  18.     {
  19.         _context = context;
  20.     }
  21. }
复制代码

  • 通过关键字 “new”
  1.  public class ApplicationDbContext : DbContext
  2. {
  3.     private readonly string _connectionString;
  4.     public ApplicationDbContext(string connectionString)
  5.     {
  6.         _connectionString = connectionString;
  7.     }
  8.     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
  9.     {
  10.         optionsBuilder.UseSqlServer(_connectionString);
  11.     }
  12. }
  13. //或者
  14. public class ApplicationDbContext : DbContext
  15. {
  16.     public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
  17.         : base(options)
  18.     {
  19.     }
  20. }
  21. var contextOptions = new DbContextOptionsBuilder<ApplicationDbContext>()
  22.     .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test")
  23.     .Options;
  24. using var context = new ApplicationDbContext(contextOptions);
复制代码
 

DBContext的属性

DbContextOptionsBuilder

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

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

允许多个具体子类使用其不同的泛型 DbContextOptions 的实例初始化DBContext
  1.  public sealed class ApplicationDbContext1 : ApplicationDbContextBase
  2. {
  3.     public ApplicationDbContext1(DbContextOptions<ApplicationDbContext1> contextOptions)
  4.         : base(contextOptions)
  5.     {
  6.     }
  7. }
  8. public sealed class ApplicationDbContext2 : ApplicationDbContextBase
  9. {
  10.     public ApplicationDbContext2(DbContextOptions<ApplicationDbContext2> contextOptions)
  11.         : base(contextOptions)
  12.     {
  13.     }
  14. }
  15.    protected ApplicationDbContext(DbContextOptions contextOptions)
  16.         : base(contextOptions)
  17.     {
  18.     }
复制代码
 

DBContext的两个关键方法

OnConfiguring配置方法

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

数据库系统配置示例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配置方法

实体的配置入口方法
  1.  
  2.     protected override void OnModelCreating(ModelBuilder modelBuilder)
  3.     {
  4.         modelBuilder.Entity<AuditEntry>();
  5.     }
复制代码
 

使用 fluent API 配置模型替代OnModelCreating

关于实体的配置,还可使用Fluent api 可在上下文中替代 OnModelCreating 方法,并使用 Fluent API 来配置模型。 此配置方法最为有效,并可在不修改实体类的情况下指定配置。 Fluent API 配置具有最高优先级,并将替代约定和数据注释。 配置按调用方法的顺序应用,如果存在任何冲突,最新调用将替代以前指定的配置。查看代码
  1.  modelBuilder.Entity<Blog>()
  2.             .Property(b => b.Url)
  3.             .IsRequired();  //代替修改实体
  4. 还有这种等等            
  5. [NotMapped]
  6. public class BlogMetadata
  7. protected override void OnModelCreating(ModelBuilder modelBuilder)
  8. {
  9.     modelBuilder.Ignore<BlogMetadata>();
  10. }
复制代码
 

DBContext的结构

模型

模型由实体类和表示数据库会话的上下文对象构成。 上下文对象允许查询并保存数据
  1.      public class BloggingContext : DbContext
  2. {
  3.     public DbSet<Blog> Blogs { get; set; }
  4.     public DbSet<Post> Posts { get; set; }
  5.     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
  6.     {
  7.         optionsBuilder.UseSqlServer(
  8.             @"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True");
  9.     }
  10. }
  11. public class Blog
  12. {
  13.     public int BlogId { get; set; }
  14.     public string Url { get; set; }
  15.     public int Rating { get; set; }
  16.     public List<Post> Posts { get; set; }
  17. }
复制代码
 

实体

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


  • 在上下文的 DbSet 属性中公开。
  • 通过实体 Blog.Posts 的导航属性发现的。
  • 在 OnModelCreating 中指定的。
  1.  internal class MyContext : DbContext
  2. {
  3.     public DbSet<Blog> Blogs { get; set; }
  4.     protected override void OnModelCreating(ModelBuilder modelBuilder)
  5.     {
  6.         modelBuilder.Entity<AuditEntry>();
  7.     }
  8. }
  9. public class Blog
  10. {
  11.     public string Url { get; set; }
  12.     public List<Post> Posts { get; set; }
  13. }
  14. public class Post
  15. {
  16.     public string Content { get; set; }
  17. }
复制代码
 

实体的属性约束

关于属性的约束,查看一下链接 实体属性 - 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个状态解释:

 
 
成员名称说明
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删除状态
 

手动设置实体状态
  1.   _mIPODataDBContext.Entry(t_TaskOrderFiles).Property(x => x.Url).IsModified = true;
  2. _mIPODataDBContext.SaveChanges();
复制代码
 

DBContext的查询方式

跟踪和不跟踪查询(AsNoTracking)
  1.  //跟踪
  2. var blog = context.Blogs.SingleOrDefault(b => b.BlogId == 1);
  3. blog.Rating = 5;
  4. context.SaveChanges();
  5. //不跟踪
  6. var blogs = context.Blogs
  7.     .AsNoTracking()
  8.     .ToList();
  9. //在上下文实例级别取消跟踪
  10. context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
复制代码
 

导航查询(Include,ThenInclude)
  1.    //同级Include,子级,更深级别的关联 ThenInclude
  2.   var blogs = context.Blogs
  3.         .Include(blog => blog.Posts)
  4.         .ThenInclude(post => post.Author)
  5.         .ToList();
复制代码
 

Inner Join查询

通过linq表达式
  1.  var query = from photo in context.Set<PersonPhoto>()
  2.             join person in context.Set<Person>()
  3.                 on new { Id = (int?)photo.PersonPhotoId, photo.Caption }
  4.                 equals new { Id = person.PhotoId, Caption = "SN" }
  5.             where b.ProjectOrderId == Guid.Parse(proIdParam.Value) && p.IsDel == false
  6.             select new { person, photo };
  7.             
  8. SELECT [p].[PersonId], [p].[Name], [p].[PhotoId], [p0].[PersonPhotoId], [p0].[Caption], [p0].[Photo]
  9. FROM [PersonPhoto] AS [p0]
  10. INNER JOIN [Person] AS [p] ON ([p0].[PersonPhotoId] = [p].[PhotoId] AND ([p0].[Caption] = N'SN'))
复制代码
 

通过lamada表达式
  1.  var query = from b in context.Set<Blog>()
  2.             from p in context.Set<Post>().Where(p => b.BlogId == p.BlogId)
  3.             select new { b, p };
  4.             
  5. SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], [p].[PostId], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Rating], [p].[Title]
  6. FROM [Blogs] AS [b]
  7. INNER JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]
复制代码
 

Left Join查询

lamada表达式
  1.  var query = from b in context.Set<Blog>()
  2.             join p in context.Set<Post>()
  3.                 on b.BlogId equals p.BlogId into grouping
  4.             from p in grouping.DefaultIfEmpty()
  5.             select new { b, p };
复制代码
 

linq表达式
  1.  var query2 = from b in context.Set<Blog>()
  2.              from p in context.Set<Post>().Where(p => b.BlogId == p.BlogId).DefaultIfEmpty()
  3.              select new { b, p };
  4. SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], [p].[PostId], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Rating], [p].[Title]
  5. FROM [Blogs] AS [b]
  6. LEFT JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]
复制代码
 

GroupJoin查询
  1.  var query = from b in context.Set<Blog>()
  2.             join p in context.Set<Post>()
  3.                 on b.BlogId equals p.BlogId into grouping
  4.             select new { b, Posts = grouping.Where(p => p.Content.Contains("EF")).ToList() };
复制代码
 

GroupBy查询
  1.  var query = from p in context.Set<Post>()
  2.             group p by p.AuthorId
  3.             into g
  4.             where g.Count() > 0
  5.             orderby g.Key
  6.             select new { g.Key, Count = g.Count() };
  7.             
  8. SELECT [p].[AuthorId] AS [Key], COUNT(*) AS [Count]
  9. FROM [Posts] AS [p]
  10. GROUP BY [p].[AuthorId]
  11. HAVING COUNT(*) > 0
  12. ORDER BY [p].[AuthorId]   
复制代码
支持的其他聚合运算符
.NETSQL
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查询
  1.   var rowsModified = context.Database.ExecuteSql($"UPDATE [Blogs] SET [Url] = NULL");
  2. var overAverageIds = context.Database
  3.     .SqlQuery<int>($"SELECT [BlogId] AS [Value] FROM [Blogs]")
  4.     .Include(b => b.Posts)
  5.     .Where(id => id > context.Blogs.Average(b => b.BlogId))
  6.     .ToList();
复制代码
 
来源:https://www.cnblogs.com/workcn/archive/2023/05/24/17427415.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具