日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

万字长文,带你彻底理解EF Core5的运行机制,让你成为团队中的EF Core专家

發布時間:2023/12/4 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 万字长文,带你彻底理解EF Core5的运行机制,让你成为团队中的EF Core专家 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在EF Core 5中,有很多方式可以窺察工作流程中發生的事情,并與該信息進行交互。這些功能點包括日志記錄,攔截,事件處理程序和一些超酷的最新出現的調試功能。EF團隊甚至從Entity Framework的第一個版本中恢復了一些有用的舊的功能。本博文帶你更深入地研究訪問EF Core 5的一些元數據和其有趣的使用方式。

1、將EF的ToTraceString移植為EF Core的ToQueryString

這是回憶殺。

在Entity Framework的第一個迭代版本中,沒有內置的日志記錄。但是有ObjectQuery.ToTraceString(),這是一種運行時方法,可以動態計算LINQ或Entity SQL查詢的SQL,盡管這不是一個很好的日志記錄方法,但它畢竟可以輸出SQL,即使在今天,也有一些有用的場景。

直到最新版本EF Core 5,該功能才成為EF Core的一部分,并且已重命名為ToQueryString()。

如果要查看實體類People的簡單查詢所生成的SQL,只需將ToQueryString附加到查詢中即可。不涉及LINQ執行方法。

換句話說,將查詢本身與執行方法分開,僅僅針對查詢。

var sqlFromQuery=context.People.ToQueryString();

ToQueryString的一個有趣用例是在調試時查看其結果,不必等到運行方法即可檢查日志中的SQL。例如我可以構建查詢,捕獲字符串,然后執行查詢。

private static void GetAllPeople() {using var context = new PeopleContext();var query = context.People.Where(p=>p.FirstName=="Julie");var sqlFromQuery = query.ToQueryString();var people = query.ToList(); }

然后在調試時,可以看到sqlFromQuery變量的預期SQL。當然您不需要將此代碼嵌入生產代碼中。實際上,也非常不建議這樣做,因為當EF Core進行SQL編制過程時,它很容易影響性能

您應該可以在調試器中調用ToQueryString,如圖所示。

在調用ToQueryString之前,查詢變量已經作為DbQuery進行了評估,因此可以正常工作。

調試上下文并在調試器中直接顯示DbSet,例如在調試器中成功運行context.People.ToQueryString(),但是您不能直接評估LINQ表達式。換句話說,如果要調試上下文變量,然后在調試器中使用Where方法,它將失敗。這并不是什么新鮮事物,也不是ToQueryString的限制。

關于ToQueryString的最后一個要點是對它的評估基于最簡單的執行:ToList。使用諸如FirstOrDefault之類的LINQ執行查詢會影響SQL的呈現方式,因此,在使用FirstOrDefault執行查詢時,ToQueryString呈現的SQL與發送給數據庫的SQL不同。這種情況下需要 EF Core日志記錄來打印準確的Sql,而不是還執拗于ToQueryString。

我發現在集成測試場景下,ToQueryString特別有用。如果您需要編寫測試,測試的成功取決于生成的SQL表達式的某些部分,那么ToQueryString是比日志記錄更簡單的路徑。使用日志記錄時,您必須將日志捕獲到文本編寫器中,然后讀取該文本。盡管使用InMemory提供程序可能很誘人,但請記住,InMemory提供程序不會生成SQL。您需要為真實數據庫使用提供程序,數據庫不需要存在即可使用ToQueryString。EF Core在內存中才能確定SQL。

這是一個演示測試示例,旨在證明EF Core編寫的智能SQL比我編寫的更為智能。請注意,我在測試項目中引用了Microsoft.EntityFrameworkCore.Sqlite提供程序。如您所知,EF和EF Core總是投影與實體屬性相關的列。它不寫SELECT *。

[TestMethod] public void SQLDoesNotContainSelectStar() {var builder = new DbContextOptionsBuilder();builder.UseSqlite("Data Source=testdb.db");using var context = new PeopleContext(builder.Options);var sql=context.People.ToQueryString();Assert.IsFalse(sql.ToUpper().Contains("SELECT *")); }

如果您使用攔截器來執行軟刪除,并且使用全局查詢過濾器來始終過濾出這些行。例如,這是我DbContext OnModelBuildling方法中的一個查詢過濾器,它告訴EF Core過濾掉IsDeleted屬性為true的Person行。

modelBuilder.Entity<Person>().HasQueryFilter(p => !p.IsDeleted);

有了這個,我可以編寫與上面類似的測試,但是將斷言更改為以下內容,以確保我不會破壞全局查詢過濾器邏輯。

Assert.IsTrue(sql.ToUpper().Contains("WHERE NOT (\"p\".\"IsDeleted\")"));

2、從EF Core記錄詳細信息

共有三種方法可以利用EF Core的日志管道。

2.1、 簡單的日志記錄

可以與.NET的日志記錄API結合使用,所有的繁重辛苦的工作都是在后臺進行的。您可以使用LogTo方法輕松配置DbContext,將.NET日志記錄輸出。

嗯,我就想看著你,就這樣子,簡簡單單。

EF Core將輸出很多事件。分為以下類,這些類從DbCloggerCategory派生。

  • 變更追蹤,ChangeTracking

  • 數據庫命令,Database.Command

  • 數據庫連接,Database.Connection

  • 數據庫事務,Database.Transaction

  • 數據庫,Database

  • 基礎設施,Infrastructure

  • 移居,Migrations

  • 模型驗證,Model.Validation

  • 模型,Model

  • 詢問,Query

  • 腳手架,Scaffolding

  • 更新,Update
    您可以使用這些類別將輸出篩選為要記錄的信息類型。

LogTo的一個參數指定目標為控制臺窗口、文件或調試窗口。
然后,第二個參數允許您通過.NET LogLevel以及您感興趣的任何DLoggerCategoy進行篩選。

此示例配置DbContext將日志輸出到控制臺,并過濾掉所有DbLoggerCategory類型LogLevel.Information組。

optionsBuilder.UseSqlServer(myConnectionString) .LogTo(Console.WriteLine,LogLevel.Information);

下面一個LogTo方法添加了第三個參數-DbLoggerCatetory數組(僅包含一個數組),以便僅對EF Core的數據庫命令進行進一步過濾。

與LogTo方法一起,我添加了EnableSensitiveDataLogging方法以在SQL中顯示傳入參數。這將捕獲所有發送到數據庫的SQL:查詢,更新,原始SQL甚至通過遷移發送的更改。

.LogTo(Console.WriteLine, LogLevel.Information,new[]{DbLoggerCategory.Database.Command.Name}, ) .EnableSensitiveDataLogging();

上面包含IsDeleted屬性的“Person”類型也具有FirstName和LastName屬性。這是添加新的Person對象后調用SaveChanges的日志。

info: 1/4/2021 17:56:09.935RelationalEventId.CommandExecuted[20101](Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (22ms) [Parameters=[ @p0='Julie' (Size = 4000), @p1='False', @p2='Lerman' (Size = 4000)],CommandType='Text',CommandTimeout='30']SET NOCOUNT ON;INSERT INTO [People] ([FirstName],[IsDeleted], [LastName])VALUES (@p0, @p1, @p2);SELECT [Id]FROM [People]WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();

日志記錄顯示信息類型、EventId、以及請求的記錄器類別的詳細信息。接下來,日志名稱,執行時間和參數列表。由于啟用了敏感數據記錄,因此將顯示參數。最后,它列出了發送到數據庫的SQL。

LogTo使EF Core輸出基本日志記錄變得容易。您可以在DbContext,ASP.NET Core應用程序的啟動文件或ASP.NET Core應用程序的應用程序配置文件中對其進行配置。

注意頂部的EventId。您甚至可以定義日志記錄以使用這些ID過濾特定事件。您還可以過濾出特定的日志類別,并且可以控制格式。在https://docs.microsoft.com/zh-cn/ef/core/logging-events-diagnostics/simple-logging上查看有關這些各種功能的更多詳細信息的文檔。

簡單日志記錄是記錄EF Core的高級方法,是的,高級的就是簡單的,這就是計算機世界的定義

您也可以通過直接與Microsoft.Extensions.Logging一起,以對EF Core的日志方式進行更多控制。檢查EF Core文檔,以獲取更多有關使用此更高級用法的詳細信息:https://docs.microsoft.com/zh-cn/ef/core/logging-events-diagnostics/extensions-logging。

2.2、響應EF Core 事件

EF Core 2.1在EF Core管道中引入了.NET事件。開始只有兩個:ChangeTracker.Tracked(在DbContext開始跟蹤實體時引發)和ChangeTracker.StateChanged(在已跟蹤的實體的狀態改變時引發)。

后來,看久了生情,事件的家族又迎來了幾個小家伙......

有了基本邏輯,團隊向EF Core 5添加三個事件:SaveChangesFailed、SaveChanges和SaveChangesAsync。

當上下文將要保存更改時,將引發DbContext.SavingChanges。
在兩個保存更改方法中的任何一個成功完成之后,將引發DbContext.SavedChanges。
DbContext.SaveChangesFailed用于捕獲和檢查故障。

能夠分離此邏輯,而不是全部填充到SaveChanges方法的中,這是一個很好的選擇。

可以使用這些事件來記錄未跟蹤的備用信息,您甚至可以使用事件來發出記錄器無法跟蹤的備用信息。

如果要使用影子屬性跟蹤審核數據,則可以在構造SQL并將其發送到數據庫之前,使用SavingChanges事件更新這些屬性。

例如,我將應用程序設置為向每個實體添加UserId陰影屬性(不包括那些屬性包和擁有的實體)。當用戶登錄時,我的應用程序有一個名為Globals.CurrentUserId的靜態變量。此外,在我的DbContext類中,我創建了一個名為SetUserId的私有方法,該方法將我的shadow屬性(存在的地方)的值設置為CurrentUserId。

private void SetUserId(object sender, SavingChangesEventArgs e) {foreach (var entry in ChangeTracker.Entries().Where(entry => entry.Metadata.GetProperty("UserId") != null)){entry.Property("UserId").CurrentValue = Globals.CurrentUserId;} }

最后,我可以將SetUserId方法連接到DbContext的構造函數中的SavingChanges事件:

public PeopleContext() {SavingChanges += SetUserId; }

現在,每當我調用SaveChanges時,UserId就會與其他數據一起持久保存到表中。

這是一些日志數據:

Executed DbCommand (29ms) [Parameters=[@p0='Julie' (Size = 4000), @p1='False', @p2='Lerman' (Size = 4000), @p3='101'], CommandType='Text', CommandTimeout='30']SET NOCOUNT ON; INSERT INTO [People] ([FirstName],[IsDeleted], [LastName], [UserId]) VALUES (@p0, @p1, @p2, @p3); SELECT [Id] FROM [People] WHERE @@ROWCOUNT = 1AND [Id] = scope_identity();

這只是利用這些事件的一種簡單方法。

2.3、使用事件計數器訪問指標

EF Core 5利用了.NET Core 3.0中.NET引入的一項很酷的功能-dotnet-counters(https://docs.microsoft.com/zh-cn/dotnet/core/diagnostics/dotnet-counters)。計數器是一個全局命令行工具。您可以使用dotnet CLI安裝此工具。

dotnet tool install --global dotnet-counters

安裝完成后,您可以告訴它監視在dotnet環境中運行的進程。您需要提供正在運行的.NET應用程序的進程ID

System.Diagnostics.Process.GetCurrentProcess().Id

在Visual Studio中,我無法簡單地在調試器中調試此值。調試器只會告訴您“此表達式會產生副作用,因此不會被評估。” 因此,我將其嵌入到我的代碼中并獲得了值313131。

在擁有ID且應用仍在運行的情況下,然后可以觸發計數器,開始監視來自Microsoft.EntityFramework命名空間的事件。如下:

dotnet counters monitor Microsoft.EntityFrameworkCore -p 313131

然后,當您遍歷應用程序時,計數器將顯示EF Core統計信息的特定列表,如圖所示,然后在應用程序執行其功能時更新計數。

我僅監視了一個小型演示應用程序,因此計數并不是很好看,但是您可以看到我正在運行一個DbContext實例(Active DbContexts),我已經運行了三個查詢,并利用了查詢緩存(因為我運行了其中一些查詢不止一次),并兩次調用SaveChanges。

這看起來像您的代碼分析工具,但是當針對更密集的解決方案運行時,它肯定會更有用。EF團隊建議您在文檔中仔細閱讀dotnet-counters功能,以便正確使用EF Core。

3、攔截EF Core的數據——攔截器

EF Core的攔截器是一項功能,該功能始于EF6,并在EF Core 3中重新引入。EF Core 5中引入了SaveChanges的新攔截器。

由于此功能已經存在很長時間了(盡管它對于EF Core是相當新的),因此應該有很多文章介紹。即使這樣,我還是覺得很神奇。

共有三種不同的攔截器類來攔截命令,連接和事務,以及用于SaveChanges的新攔截器類。每個類都有自己相關的虛擬方法(和相關對象)。例如,DbCommandInterceptor公開了ReaderExecuting和ReaderExecutingAsync,它們在命令即將發送到數據庫時被觸發。

public override InterceptionResult<DbDataReader>ReaderExecuting(DbCommand command,CommandEventData eventData,InterceptionResult<DbDataReader> result){//例如,webmote支持你干點啥?return result;}

它的參數之一是DbCommand,其CommandText屬性保存SQL。

如果要修改SQL,添加查詢提示或其他任務,則可以更改命令,然后使用新CommandText值的命令將繼續進行。

從數據庫返回任何結果數據時,將觸發ReaderExecuted / Async方法。

public override DbDataReader ReaderExecuted(DbCommand command,CommandExecutedEventData eventData,DbDataReader result){return base.ReaderExecuted(command, eventData, result);}

例如,在這里您可以捕獲DbDataReader,并對該數據進行某些處理,然后再繼續執行EF Core實現。一個示例是記錄一些記錄器無法捕獲的內容,例如:

4、查詢攔截

EF Core 公開的?DbCommandInterceptor攔截器提供查詢攔截功能,查詢攔截是在數據庫上執行查詢之前插入邏輯,或者在查詢執行之后(以及控制返回到調用代碼之前)立即插入邏輯的能力。

此功能在現實世界中有多種使用案例:

  • 延長具有某些特征的命令的超時

  • 查詢失敗并記錄異常時診斷信息

  • 當讀取到內存的行數超過特定閾值時,記錄警告

一個小例子:

public class TestQueryInterceptor : DbCommandInterceptor {// runs before a query is executedpublic override InterceptionResult<DbDataReader> ReaderExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result){command.CommandText += " OPTION (OPTIMIZE FOR UNKNOWN)"; command.CommandTimeout = 12345; return result;}// runs after a query is excutedpublic override DbDataReader ReaderExecuted(DbCommand command, CommandExecutedEventData eventData, DbDataReader result){if (this.ShouldChangeResult(command, out var changedResult)){return changedResult;}return result;} }

注意:?大多數方法都有同步和異步版本。令人討厭的是,異步查詢僅觸發異步方法(反之亦然),因此在編寫攔截器時必須覆蓋兩者。

安裝攔截器是很簡單的。

public class SampleDbContext : DbContext {protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){optionsBuilder.UseSqlite(@"Data Source=Sample.db;").AddInterceptors(new TestQueryInterceptor (), new SampleInterceptor2());} }

通過返回InterceptionResult<T>.SuppressWithResult()禁止執行。重要的是要注意,DbCommandInterceptor安裝的其他所有組件仍將執行,并且可以通過上的HasResult屬性檢查其他攔截器是否已禁止執行result。

public override InterceptionResult<object> ScalarExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<object> result) {if (this.ShouldSuppressExecution(command)){return InterceptionResult.SuppressWithResult<object>(null);}return result; }

方法中引發的異常從技術上將阻止執行,不要利用這個事實,將異常用于控制流幾乎總是很糟糕的設計。

你可以攔截如下清單的操作:

方法操作
CommandCreating在創建命令之前(注意:一切都是命令,因此它將攔截所有查詢)
CommandCreated創建命令之后但執行之前
CommandFailed[Async]在執行過程中命令失敗并出現異常后
ReaderExecuting[Async]在執行“查詢”命令之前
ReaderExecuted[Async]執行“查詢”命令后
NonQueryExecuting[Async]在執行“非查詢”命令之前(注意:非查詢的一個示例是 ExecuteSqlRaw
NonQueryExecuted[Async]執行“非查詢”命令后
ScalarExecuting [Async]在執行“標量”命令之前(注意:“標量”是存儲過程的同義詞)
ScalarExecuted [Async]執行“標量”命令后
DataReaderDispose執行命令后

這是一個耗時命令攔截

public class MyDBCommandInterceptor: DbCommandInterceptor {public static ConcurrentDictionary CommandStartTimes = new ConcurrentDictionary();public static ConcurrentDictionary CommandDurations = new ConcurrentDictionary();public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext) {CommandStartTimes.TryAdd(command, DateTime.Now);base.NonQueryExecuting(command, interceptionContext);}public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext) {CommandStartTimes.TryAdd(command, DateTime.Now);base.ReaderExecuting(command, interceptionContext);}public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext) {CommandStartTimes.TryAdd(command, DateTime.Now);base.ScalarExecuting(command, interceptionContext);}public override void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext interceptionContext) {base.NonQueryExecuted(command, interceptionContext);AccumulateTime(command);}public override void ReaderExecuted(DbCommand command, DbCommandInterceptionContext interceptionContext) {base.ReaderExecuted(command, interceptionContext);AccumulateTime(command);}public override void ScalarExecuted(DbCommand command, DbCommandInterceptionContext interceptionContext) {base.ScalarExecuted(command, interceptionContext);AccumulateTime(command);}private void AccumulateTime(DbCommand command) {if (CommandStartTimes.TryRemove(command, outvar commandStartTime)) {var commandDuration = DateTime.Now - commandStartTime;CommandDurations.AddOrUpdate(command.CommandText, commandDuration, (_, accumulated) => commandDuration + accumulated);}} }

有關使用EF Core文檔中的攔截器的大量指導,請訪問https://docs.microsoft.com/en-us/ef/core/logging-events-diagnostics/interceptors。

5、EF Core 5中的Sleeper功能:調試視圖

就是?ChangeTracker.DebugView和Model.DebugView。

DebugViews輸出格式正確的字符串,其中有ChangeTracker的狀態或模型中的元數據的信息。DebugView提供了一個漂亮的文檔,您可以捕獲和打印該文檔,并真正了解其幕后情況。

我在調試器上花費了大量時間,以探索有關變更跟蹤器了解的內容或EF Core如何解釋我所描述的模型的各種詳細信息。能夠以這種文本格式讀取此信息,甚至將其保存在文件中,因此您無需反復調試即可收集詳細信息,這是EF Core 5的一項神奇功能

確保您了解DebugViews是撰寫本文的目的。

在DbContext.ChangeTracker.DebugView中,您將找到ShortView和LongView屬性。例如,這里是我剛查詢一個Person對象時的視圖,而我的上下文僅包含一個人。

Person {Id: 1} Unchanged

這是最常用的信息-在我的上下文中,只有一個未更改的Person的ID為1。

LongView提供了有關被跟蹤實體的更多詳細信息。

Person {Id: 1} UnchangedId: 1 PKFirstName: 'Julie'IsDeleted: 'False'LastName: 'Lerman'UserId: 101Addresses: []

如果要在跟蹤的Person上對其進行編輯并強制上下文檢測更改,則LongView除了將狀態顯示為Modified之外,還對LastName屬性所做的更改進行記錄。

Person {Id: 1} ModifiedId: 1 PKFirstName: 'Julie'IsDeleted: 'False'LastName: 'Lermantov' ModifiedOriginally 'Lerman'UserId: 101Addresses: []

您可以在此視圖中看到一個Addresses屬性。實際上,使用導航,“人”和“地址”之間存在多對多關系。EF Core在運行時推斷內存中的PersonAddress實體,以便將關系數據持久化到聯接表中。

當我在其“地址”集合中創建一個具有一個地址的人的圖形時,您可以在ShortView中看到一個“人”,一個地址和一個推斷的PersonAddress對象。長視圖顯示了這些對象的屬性。

AddressPerson (Dictionary<string, object>){AddressesId: 1, ResidentsId: 1} Unchanged FK{AddressesId: 1} FK {ResidentsId: 1} Address {Id: 1} Unchanged Person {Id: 1} Modified

我喜歡這些調試視圖,這些視圖可以在調試時幫助我發現被跟蹤對象的狀態和關系,無論我是在解決問題還是在學習它的工作方式。

讓我們轉到Model.DebugViews看看您可以從中學到什么。

首先,我應該闡明我的模型。使用Visual Studio中的EF Core Power Tools擴展來可視化模型。

DbContext.Model.DebugView也具有ShortView和LongView。它們都包含很多信息。

您可以看到屬性,主鍵和外鍵,索引以及級聯刪除規則,多對多關系,甚至指定了它使用跳過導航。還描述了繼承。您可以從這份文件中學到很多東西。

  • 清單1:數據模型的Model.DebugView.ShortView

Model:EntityType: AddressPerson (Dictionary<string, object>) CLR Type: Dictionary<string, object>Properties:AddressesId (no field, int) Indexer Required PK FK AfterSave:ThrowResidentsId (no field, int) Indexer Required PK FK Index AfterSave:ThrowKeys:AddressesId, ResidentsId PKForeign keys:AddressPerson (Dictionary<string, object>) {'AddressesId'} -> Address {'Id'} CascadeAddressPerson (Dictionary<string, object>) {'ResidentsId'} -> Person {'Id'} CascadeIndexes:ResidentsIdEntityType: AddressProperties:Id (int) Required PK AfterSave:Throw ValueGenerated.OnAddPostalCode (string)Street (string)UserId (no field, int) Shadow RequiredNavigations:WildlifeSightings (List<WildlifeSighting>) Collection ToDependent WildlifeSightingSkip navigations:Residents (List<Person>) CollectionPerson Inverse: AddressesKeys:Id PKEntityType: PersonProperties:Id (int) Required PK AfterSave:Throw ValueGenerated.OnAddFirstName (string)IsDeleted (bool) RequiredLastName (string)UserId (no field, int) Shadow RequiredSkip navigations:Addresses (List<Address>) CollectionAddress Inverse: ResidentsKeys:Id PKEntityType: WildlifeSightingProperties:Id (int) Required PK AfterSave:Throw ValueGenerated.OnAddAddressId (int) Required FK IndexDateTime (DateTime) RequiredDescription (string)UserId (no field, int) Shadow RequiredKeys:Id PKForeign keys:WildlifeSighting {'AddressId'} -> Address {'Id'} ToDependent: WildlifeSightings CascadeIndexes:AddressId

Model.DebugView.LongView包含更多詳細信息,它們描述了注釋,數據庫映射等。您可以從LongView中學到更多,但并不是每個人都希望看到這種細節,如果您需要,它就在那里。

  • 清單2:在Model.DebugView的LongView中描述的Person實體

EntityType: PersonProperties:Id (int) Required PK AfterSave:Throw ValueGenerated.OnAddAnnotations:Relational:DefaultColumnMappings: System.Collections.Generic.SortedSet`1 [Microsoft.EntityFrameworkCore.Metadata.Internal.ColumnMappingBase]Relational:TableColumnMappings: System.Collections.Generic.SortedSet`1 [Microsoft.EntityFrameworkCore.Metadata.Internal.ColumnMapping]SqlServer:ValueGenerationStrategy: IdentityColumnFirstName (string)Annotations:Relational:DefaultColumnMappings: System.Collections.Generic.SortedSet`1[Microsoft.EntityFrameworkCore.Metadata.Internal.ColumnMappingBase]Relational:TableColumnMappings:System.Collections.Generic.SortedSet`1[Microsoft.EntityFrameworkCore.Metadata.Internal.ColumnMapping]IsDeleted (bool) RequiredAnnotations:Relational:DefaultColumnMappings: System.Collections.Generic.SortedSet`1[Microsoft.EntityFrameworkCore.Metadata.Internal.ColumnMappingBase]Relational:TableColumnMappings: System.Collections.Generic.SortedSet`1[Microsoft.EntityFrameworkCore.Metadata.Internal.ColumnMapping]LastName (string)Annotations:Relational:DefaultColumnMappings: System.Collections.Generic.SortedSet`1[Microsoft.EntityFrameworkCore.Metadata.Internal.ColumnMappingBase]Relational:TableColumnMappings: System.Collections.Generic.SortedSet`1[Microsoft.EntityFrameworkCore.Metadata.Internal.ColumnMapping]UserId (no field, int) Shadow RequiredAnnotations:Relational:DefaultColumnMappings: System.Collections.Generic.SortedSet`1[Microsoft.EntityFrameworkCore.Metadata.Internal.ColumnMappingBase]Relational:TableColumnMappings: System.Collections.Generic.SortedSet`1[Microsoft.EntityFrameworkCore.Metadata.Internal.ColumnMapping]Skip navigations:Addresses (List<Address>) CollectionAddress Inverse: ResidentsKeys:Id PKAnnotations:Relational:UniqueConstraintMappings: System.Collections.Generic.SortedSet`1[Microsoft.EntityFrameworkCore.Metadata.Internal.UniqueConstraint]Annotations:ConstructorBinding: Microsoft.EntityFrameworkCore.Metadata.ConstructorBindingQueryFilter: p => Not(p.IsDeleted)Relational:DefaultMappings: System.Collections.Generic.List`1[Microsoft.EntityFrameworkCore.Metadata.Internal.TableMappingBase]Relational:TableMappings: System.Collections.Generic.List`1[Microsoft.EntityFrameworkCore.Metadata.Internal.TableMapping]Relational:TableName: PeopleServiceOnlyConstructorBinding: Microsoft.EntityFrameworkCore.Metadata.ConstructorBinding

6、利用

有關EF Core,您對幕后情況了解得越多,對該工具的掌控力就越大。

了解EF Core如何解釋您的類和映射,你可以控制這些模型并按照您希望的方式持久保存數據,也可以根據需要修改SQL甚至結果。學習如何利用本文中介紹的各種調試,日志記錄,偵聽和事件處理方法,希望能幫助您成為團隊中的EF Core專家。

當然,不用多久,你就會升職加薪、當上總經理、出任CEO、迎娶白富美、走上人生巔峰,想想是不是還有點小激動?

總結

以上是生活随笔為你收集整理的万字长文,带你彻底理解EF Core5的运行机制,让你成为团队中的EF Core专家的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久精品一区二区免费播放 | 国产伦精品一区二区三区四区免费 | 波多野结衣国产在线 | 少女与动物高清版在线观看 | 国产高清自拍一区 | 99热在线只有精品 | 欧美另类69 | 亚洲制服一区二区 | 特级淫片aaaaaaa级附近的 | 精品久久久久久久久久岛国gif | 狠狠狠狠狠干 | 天天搞天天 | 日本一区二区三区在线免费观看 | 色狠狠久久av大岛优香 | 91美女视频在线观看 | 又黄又爽一区二区三区 | 国产精品成av人在线视午夜片 | 一级片久久 | 一级成人免费视频 | 蜜臀99久久精品久久久久久软件 | 亚洲精品一区二区三区婷婷月 | 欧美群妇大交乱 | 久青草视频在线 | 91操操| 大黑人交xxx极品hd | 日韩激情欧美 | aa视频在线 | 国产福利免费在线观看 | 欧美精品一区二区三区四区五区 | 亚洲社区在线 | 成人在线视频一区 | 亚洲字幕av一区二区三区四区 | 91禁看片 | 男女国产视频 | 日韩电影一区二区三区四区 | 97免费观看视频 | 久久人人爽天天玩人人妻精品 | 无码h肉动漫在线观看 | 欧美亚洲另类图片 | 51热门大瓜今日大瓜 | 亚洲欧美综合精品久久成人 | 国产成人在线视频播放 | 亚洲av日韩av在线观看 | 黄色av网站在线免费观看 | 久久偷看各类wc女厕嘘嘘偷窃 | av在线视屏| 日韩色在线观看 | 欧美精品在线免费 | 久久桃花网| 午夜嘿嘿嘿 | 青青五月天 | 亚洲欧美另类激情 | 成人3d动漫一区二区三区 | 一级美女大片 | 亚洲熟乱 | 深夜影院在线观看 | 97国产在线| 色偷偷噜噜噜亚洲男人的天堂 | 人妻无码中文久久久久专区 | 无码视频在线观看 | 国产成人免费网站 | 一级黄色美女 | 欧美日韩一区二区中文字幕 | 探花视频在线免费观看 | 欧美日b视频 | 色天使亚洲 | 97精品一区二区三区 | 久久偷看各类女兵18女厕嘘嘘 | 日韩精美视频 | 成人免费毛片日本片视频 | 国产老妇伦国产熟女老妇视频 | 国产麻豆精品在线 | 疯狂揉花蒂控制高潮h | 国产精品久久久久久av | 日出白浆视频 | 欧美日韩激情在线观看 | 韩国三级在线看 | 外国电影免费观看高清完整版 | 影音先锋三级 | 中文区中文字幕免费看 | 国产精品剧情 | 欧美日韩三级视频 | 无码免费一区二区三区免费播放 | 国产v亚洲v天堂无码久久久 | 久久久久久国产免费a片 | 奶水旺盛的女人伦理 | 无码国产伦一区二区三区视频 | 中文字幕乱码一区 | 国产一区资源 | 亚洲天堂aaa | 女厕厕露p撒尿八个少妇 | 欧美大胆视频 | 国产亚洲AV无码成人网站在线 | 狠狠看 | 破处视频在线观看 | 极品色av影院 | 中文字字幕码一二三区 | 国产毛片基地 | 亚洲精品v天堂中文字幕 |