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
  • MQTTnet 是一個高性能的MQTT類庫,支持.NET Core和.NET Framework。 MQTTnet 原理: MQTTnet 是一個用於.NET的高性能MQTT類庫,實現了MQTT協議的各個層級,包括連接、會話、發佈/訂閱、QoS(服務質量)等。其原理涉及以下關鍵概念: MqttCli ...
  • 在WPF中,源屬性(Source Property)指的是提供數據的屬性,通常是數據模型或者其他控制項的屬性,而目標屬性(Target Property)則是數據綁定的目標,通常是綁定到控制項的屬性,例如TextBlock的Text屬性。數據綁定將源屬性的值自動更新到目標屬性中。 主要包含以下幾個事件: ...
  • async/await 是 C# 中非同步編程的關鍵特性,它使得非同步代碼編寫更為簡單和直觀。下麵深入詳細描述了 async/await 的使用場景、優點以及一些高級使用方法,並提供了相應的實例源代碼。 使用場景: I/O 操作: 非同步編程特別適用於涉及 I/O 操作(如文件讀寫、網路請求等)的場景。在 ...
  • 使用過office的visio軟體畫圖的小伙伴都知道,畫圖軟體分為兩部分,左側圖形庫,存放各種圖標,右側是一個畫布,將左側圖形庫的圖標控制項拖拽到右側畫布,就會生成一個新的控制項,並且可以自由拖動。那如何在WPF程式中,實現類似的功能呢?今天就以一個簡單的小例子,簡述如何在WPF中實現控制項的拖拽和拖動,... ...
  • 1、Blazor Hybrid簡介 Blazor Hybrid 使開發人員能夠將桌面和移動本機客戶端框架與 .NET 和 Blazor 結合使用。在 Blazor Hybrid 應用中,Razor 組件在設備上是本機運行的。 這些組件通過本地互操作通道呈現到嵌入式 Web 視圖控制項。 組件不在瀏覽器 ...
  • 除了內置的數據集,scikit-learn還提供了隨機樣本的生成器。通過這些生成器函數,可以生成具有特定特性和分佈的隨機數據集,以幫助進行機器學習演算法的研究、測試和比較。 目前,scikit-learn庫(v1.3.0版)中有20個不同的生成樣本的函數。本篇重點介紹其中幾個具有代表性的函數。 1. ...
  • 從0到1,手把手帶你開發截圖工具ScreenCap------002實現通過文件對話框,選擇合適的文件夾,自定義預設的圖片保存位置,簡單易學 ...
  • 每次談到容器的時候,除了Docker之外,都會說起 Kubernetes,那麼什麼是 Kubernetes呢?今天就來一起學快速入門一下 Kubernetes 吧!希望本文對您有所幫助。 Kubernetes,一種用於管理和自動化雲中容器化工作負載的工具。 想象一下你有一個管弦樂隊,將每個音樂家視為 ...
  • 目錄 基本說明 安裝 Nginx 部署 VUE 前端 部署 Django 後端 Django admin 靜態文件(CSS,JS等)丟失的問題 總結 1. 基本說明 本文介紹了在 windows 伺服器下,通過 Nginx 部署 VUE + Django 前後端分離項目。本項目前端運行在 80 埠 ...
  • 從0到1,手把手帶你開發截圖工具ScreenCap------003實現最小化程式到托盤運行,- 為了方便截圖乾凈,實現最小化程式到托盤運行,簡潔,勿擾,實現最小化程式到托盤運行, 實現托盤菜單功能,實現回顯主窗體, 實現托盤開始截屏, 實現氣泡信息提示,實現托盤程式提示,實現托盤退出程式, 封裝完... ...