Entity Framework的最佳实践一

这篇具有很好参考价值的文章主要介绍了Entity Framework的最佳实践一。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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

 文章来源地址https://www.toymoban.com/news/detail-457177.html

实体

在上下文中包含一种类型的 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个状态解释:

 
Entity Framework的最佳实践一
 
成员名称
说明
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();

实体的状态查看

如果需要查看实体的跟踪变更状态可以通过以下方式,在控制台输出;
详情API
DBContext.Entry(instanceObj).DebugView 
或者 
context.ChangeTracker.DetectChanges(); Console.WriteLine(context.ChangeTracker.DebugView.LongView);

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();

DBContext增删改

  • 增删改均需要依赖主键,如果没有主键,EF则不可用
  • 先看DBContext是否有跟踪属性,如果有跟踪则不需要手动维护attach状态
--删除和添加均不需要Attach,会自动识别状态
DBContext.Add()
DBContext.AddRange()
DBContext.SaveChange()

DBContext.Remove()
DBContext.RemoveRange()
DBContext.SaveChange()

--修改分为两种,一种是new的新对象,一种是从数据库查出来的对象
--如果是new的新对象,需要先修改Attach,使其跟踪; 若果是从数据库查出则不用attach
DBContext.Attach<Class>(item)

----新New对象
------更新指定列 
DBContext.Attach<Class>(item)
item.Propertry = '' //当对象Attach后,被跟踪时,则EF会自动判断属性的变化,我们不需要再手动指定变更列;此时比对的是新New对象的属性是否变化(非数据库的列属性)
DBContext.SaveChange()
------更新全部列
DBContext.Update(item)  //全部属性都会变更
DBContext.SaveChange()

----从数据库查出对象
------更新指定列 
item.Propertry = '' //当对象已被跟踪时,则EF会自动判断属性的变化,我们不需要再手动指定变更列;此时比对的是数据库的列属性是否变化
DBContext.SaveChange()
------更新全部列
DBContext.Update(item)  //全部属性都会变更
DBContext.SaveChange()

----想要查看SaveChanges转化的sql时,请参阅文章中关于实体的状态查看章节
 

DBcontext与多线程

EF Core不是线程安全,不支持在同一上下文实例上运行多个并行操作,包括多线程以及异步操作,但支持异步等待操作;
说人话就是,一个DBContext实例不能跨多个线程使用;就相当于你不能同时存在在两个地方

到了这里,关于Entity Framework的最佳实践一的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【c#,.NET】Entity Framework Core基础详解

    目录   一、EF Core概述 1.1 什么是ORM?  1.2 EF Core的性能怎么样  二、EF Core入门 2.1 什么是Migration数据库迁移: 2.2  EF Core数据的增删改查 2.2.1 增加数据 2.2.2 查询数据  2.2.3 修改和删除数据 三、EF Core的实体类配置 3.1 约定大于配置 3.2 EF Core两种配置方式 3.2.1 Data Annotation 3.2.2 

    2024年02月04日
    浏览(52)
  • ASP.NET中使用Entity Framework(EF)关联表查询

    在ASP.NET中使用Entity Framework(EF)进行关联表查询的具体步骤如下: 配置数据库上下文(DbContext):在 DbContext 派生类中,使用 DbSetT 属性表示每个实体对应的数据库表。确保每个实体类和关系都正确映射到数据库表。 定义关联表之间的导航属性:在实体类中,使用导航属性表

    2024年02月14日
    浏览(41)
  • 【C# .NET 】使用 Entity Framework Core 操作sqlite数据库

    添加包 EF Core design package   NuGet Gallery | Home 使用用于 EF Core 迁移和现有数据库中的反向工程(基架)的工具需要安装相应的工具包: 可在 Visual Studio 包管理器控制台中使用的 PowerShell 工具的 Microsoft.EntityFrameworkCore.Tools 跨平台命令行工具的 dotnet-ef 和 Microsoft.EntityFramewor

    2024年02月14日
    浏览(44)
  • 杨中科 .NETCORE ENTITY FRAMEWORK CORE-1 EFCORE 第一部分

    1、说明: 本课程需要你有数据库、SOL等基础知识。 2、ORM: ObjectRelational Mapping。让开发者用对象操作的形式操作关系数据库 比如插入: 比如查询: 3、有哪些ORM: EF core(官方推荐)、Dapper、SqlSugar、FreeSql等 1、Entity Framework Core(EF Coxe)是微软官方的ORM框架优点: 功能强大、官方支持、生

    2024年02月02日
    浏览(50)
  • 【Entity Framework】你必须要了解EF中数据查询之数据加载

    Entity Framework Core 允许在模型中使用导航属性来加载关联实体。有三种常见的O/RM模式可用于加载关联数据。 预先加载表示从数据库中加载关联数据,作为初始查询的一部分; 显示加载表示稍后从数据库中显示加载关联数据; 延迟加载表示在访问导航属性时,从数据库中以透

    2024年04月17日
    浏览(71)
  • .NET Core Entity Framework Core 多线程中使用Context报错问题

    本文主要介绍Entity Framework Core在ASP.NET Core中,多个请求中使用同一个context问题,Entity Framework Core上下文(context)不能在多线程中使用,多个请求其实就是多个线程。报错信息:InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members a

    2024年02月07日
    浏览(58)
  • .Net Core Entity Framework Core 的基础封装 -数据库操作拦截器

    自己制作的一个基于Entity Framework Core 的数据库操作拦截器,可以打印数据库执行sql,方便开发调试,代码如下: 运行结果如下:  

    2024年02月22日
    浏览(41)
  • ETF场内基金:AI量化投资最佳切入点(数据篇)

    原创文章第77篇,专注“个人成长与财富自由、世界运作的逻辑, AI量化投资”。 关于量化的基础知识,前面说得差不多了。 后面要开始实战。 量化的细分市场很多,如下图所示: 再从风险收益来看,从基金到加密货币,从“保守”到“激进”。 这里指的保守,当然是“主

    2024年01月21日
    浏览(41)
  • ASP.Net Core Web API结合Entity Framework Core框架(API的创建使用,接口前端权限设置,前端获取API的Get,post方法)(程序包引用以及导入数据库)

    目录 1. Web Api 程序包引用 2. Web Api 的创建与Http类型的介绍 2.1 ASP.Net Core Web API项目的创建 2 .2  API接口的创建 2.3 HttpGet和HttpPost类型的区别 3.接口权限设置 4.HttpGet方法和HttpPOst方法 5.前端中用HttpGet/Poset获取接口数据 6.EF框架——配置数据库链接字符串(即将数据库中的表导入项

    2024年02月08日
    浏览(52)
  • 43 最佳实践-性能最佳实践-IOThread配置

    43.1 概述 KVM平台上,对虚拟磁盘的读写在后端默认由QEMU主线程负责处理。这样会造成如下问题: 虚拟机的I/O请求都由一个QEMU主线程进行处理,因此单线程的CPU利用率成为虚拟机I/O性能的瓶颈。 虚拟机I/O在QEMU主线程处理时会持有QEMU全局锁(qemu_global_mutex),一旦I/O处理耗时较长

    2024年02月08日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包