Entity Framework的最佳實踐一

来源:https://www.cnblogs.com/workcn/archive/2023/05/24/17427415.html
-Advertisement-
Play Games

文件比較平常都是用Beyond Compare,可以說離不開的神器,特別是針對代碼比較這塊,確實挺好用的。 不過Beyond Compare平常拿它主要是用來做代碼比較,用來做一些大批量的二進位文件比較,其實有點不是很方便。 於是造輪子,重新寫了一個簡單的文件夾比較的小工具。 平常主要是拿來做一些N ...


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();
 
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、準備一下 開發環境 Pycharm python 3.8 ffmpeg 模塊的使用 requests re subprocess 二、基本思路流程 1、明確需求 採集下破站視頻數據通過開發者工具進行抓包分析,分析破站視頻數據的來源。 開發者工具的使用 打開方式: 滑鼠右鍵點擊檢查選擇Networ ...
  • ## 前言 如題,這個小玩意,就是不限制你查的是哪張表,用的是什麼類。 我直接一把梭,嘎嘎給你一頓導出。 我知道,這是很多人都想過的, 至少我就收到很多人問過我這個類似的問題。 我也跟他們說了,但是他們就是不動手,其實真的很簡單。 不動手怎麼辦? 我出手唄。 不多說開搞 。 ## 正文 玩法很簡單。 ...
  • # 超輕量級 DynamicTableNameInnerInterceptor是mybatis-plug的一個攔截器插件,可以自己定義需要攔截的表單,然後對它進行加工,這時mybatis-plus就會把SQL代碼的表名加上你的這個裝飾。 # 封裝的思想 我們通常把mybatis做成一個包,公司其它同 ...
  • 用`markdown`寫文檔很方便,但是有個困擾的地方,就是標題的編號問題。 寫文檔的時候,經常會在中間插入新的標題和內容,所以手動管理編號的話,如果新的標題插在前面,則要調整後面所有的編號。 如果在文檔完成後再手動加上編號的話,不僅容易忘記, 而且有時候我們是在其他編輯器里編輯文檔再導出`mark ...
  • # 一、環境準備 Netty需要的運行環境很簡單,只有2個。 - JDK 1.8+ - Apache Maven 3.3.9+ # 二、Netty 客戶端/伺服器概覽 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/c49191e6ee6e448f8c525b450 ...
  • # 原因 當mysql資料庫單表大於1千萬以後,查詢的性能就不能保證了,我們必須考慮分庫,分表的方案了,還好,sharding-jdbc可以很優雅的與springboot對接,完成對mysql的分庫和分表。 # 依賴整理 > 為了不影響其它小容量的表,所有添加了動態數據源,只對需要分庫分表的進行配置 ...
  • # Maven的概述 @[toc] Java 項目開發過程中,構建指的是使用『原材料生產產品』的過程。 - 原材料 - Java 源代碼 - 基於 HTML 的 Thymeleaf 文件 - 圖片 - 配置文件 - …… - 產品 - 一個可以在伺服器上運行的項目 構建過程包含的主要的環節: - 清 ...
  • > ML.Net - 開源的跨平臺機器學習框架 > - 支持CPU/GPU訓練 > - 輕鬆簡潔的預測代碼 > - 可擴展其他的機器學習平臺 > - 跨平臺 ![img](https://img2023.cnblogs.com/blog/1339560/202305/1339560-20230524 ...
一周排行
    -Advertisement-
    Play Games
  • 在一些複雜的業務表中間查詢數據,有時候操作會比較複雜一些,不過基於SqlSugar的相關操作,處理的代碼會比較簡單一些,以前我在隨筆《基於SqlSugar的開發框架循序漸進介紹(2)-- 基於中間表的查詢處理》介紹過基於主表和中間表的聯合查詢,而往往實際會比這個會複雜一些。本篇隨筆介紹聯合多個表進行... ...
  • 從按鈕、文本框到下拉框、列表框,WPF提供了一系列常用控制項,每個控制項都有自己獨特的特性和用途。通過靈活的佈局容器,如網格、堆棧面板和換行面板,我們可以將這些控制項組合在一起,實現複雜的界面佈局。而通過樣式和模板,我們可以輕鬆地定製控制項的外觀和行為,以符合我們的設計需求。本篇記錄WPF入門需要瞭解的樣式... ...
  • 以MySQL資料庫為例 # 一. 安裝 NuGet搜索Dapper.Lite並安裝最新版本。 ![](https://img2023.cnblogs.com/blog/174862/202306/174862-20230602155913303-757935399.jpg) NuGet搜索MySql ...
  • # 圖片介面JWT鑒權實現 # 前言 之前做了個返回圖片鏈接的介面,然後沒做授權,然後今天鍵盤到了,也是用JWT來做介面的許可權控制。 然後JTW網上已經有很多文章來說怎麼用了,這裡就不做多的解釋了,如果不懂的可以參考下列鏈接的 文章。 圖片介面文章:[還在愁個人博客沒有圖片放?](https://w ...
  • ![線程各屬性縱覽](https://img2023.cnblogs.com/blog/1220983/202306/1220983-20230603114109107-477345835.png) 如上圖所示,線程有四個屬性: - 線程ID - 線程名稱 - 守護線程 - 線程優先順序 ### 1. ...
  • 本次主要介紹golang中的標準庫`bytes`,基本上參考了 [位元組 | bytes](https://cloud.tencent.com/developer/section/1140520) 、[Golang標準庫——bytes](https://www.jianshu.com/p/e6f7f2 ...
  • 歡迎來到本篇文章!通過上一篇什麼是 Spring?為什麼學它?的學習,我們知道了 Spring 的基本概念,知道什麼是 Spring,以及為什麼學習 Spring。今天,這篇就來說說 Spring 中的核心概念之一 IoC。 ...
  • # 2022版本IDEA+Maven+Tomcat的第一個程式(傻瓜教學) ​ 作為學習Javaweb的一個重要環節,如何實現在IDEA中利用Maven工具創建一個Javaweb程式模版並連接Tomcat發佈是非常重要的。我比較愚鈍(小白),而且自身電腦先前運行過spring或maven的程式,系統 ...
  • 本篇專門扯一下有關 QCheckBox 組件的一個問題。老周不水字數,直接上程式,你看了就明白。 #include <QApplication> #include <QWidget> #include <QPushButton> #include <QCheckBox> #include <QVBo ...
  • # 1.列表數據元素排序 在創建的列表中,數據元素的排列順序常常是無法預測的。這雖然在大多數情況下都是不可避免的,但經常需要以特定的順序呈現信息。有時候希望保留列表數據元素最初的排列順序,而有時候又需要調整排列順序。python提供了很多列表數據元素排序的方式,可根據情況選用。 ## 1.永久性排序 ...