EF Core 3 的 40 个中断性变更
為了修復(fù) Entify Framework Core 中許多已發(fā)現(xiàn)的缺陷,微軟在 EF Core 3 中引入了 40 個(gè)中斷性變更。我們可以在微軟文檔中查看完整的中斷性變更列表,本文僅列舉幾個(gè)主要的點(diǎn)。
客戶(hù)端查詢(xún)
為了突破 EF Core SQL 生成器的限制,默認(rèn)只在客戶(hù)端執(zhí)行部分查詢(xún)。這意味著對(duì)于部分不能轉(zhuǎn)換成 SQL 的 LINQ 查詢(xún),需要從數(shù)據(jù)庫(kù)加載數(shù)據(jù)表,并在內(nèi)存中執(zhí)行其余的操作。在 2.1 版本之前,Group By 都是在客戶(hù)端執(zhí)行的。
這種方式的缺點(diǎn)是,Where() 子句中的一個(gè)問(wèn)題可能導(dǎo)致 EF Core 加載整張數(shù)據(jù)表。開(kāi)發(fā)人員還發(fā)現(xiàn),在無(wú)法生成相關(guān)子查詢(xún)的情況下,它將執(zhí)行成百上千個(gè)二級(jí)查詢(xún)。
新的默認(rèn)行為是 EF Core 僅允許在客戶(hù)端執(zhí)行最終的 Select() 操作。如果 EF Core 不能生成正確的 SQL,將引發(fā)異常。開(kāi)發(fā)人員可以覆蓋這個(gè)行為,但微軟更希望開(kāi)發(fā)者遇到這個(gè)問(wèn)題時(shí)先嘗試提交一個(gè) bug 請(qǐng)求。
可以在“3.0 查詢(xún)指導(dǎo)原則大綱和決策點(diǎn)“中了解更多有關(guān)該變更的信息。
參數(shù)化及插值 SQL
正如我們?cè)?2017 年報(bào)告的那樣,EF Core 的字符串插值特性引起了許多關(guān)注。使用該特性可以將內(nèi)插字符串自動(dòng)轉(zhuǎn)換為參數(shù)化 SQL,但前提是這些字符串之前沒(méi)有被存儲(chǔ)在臨時(shí)變量中。
v1 = context.Customers.FromSql($"SELECT * FROM Customers WHERE City = {city}")
var sql = $"SELECT * FROM Customers WHERE City = {city}"
v2 = context.Customers.FromSql(sql)
在上面的例子中,v1 是正確參數(shù)化的,而 v2 則引入了一個(gè) SQL 注入漏洞。
為了消除上述漏洞,將移除 FromSql 函數(shù),并使用 FromSqlRawand 和 FromSqlInterpolated 替代。
臨時(shí)鍵
EF Core 通常會(huì)創(chuàng)建臨時(shí)主鍵來(lái)跟蹤新實(shí)體。這些臨時(shí)主鍵以負(fù)數(shù)的形式存儲(chǔ)在鍵屬性中(例如 CustomerKey 或 OrderId)。理論上,這些臨時(shí)主鍵在生成時(shí)會(huì)被真正的鍵所替換,不過(guò)也存在幾個(gè)例外情況,比如那些在用戶(hù)界面上顯示的假鍵甚至?xí)槐4娴綌?shù)據(jù)庫(kù)中。
EF Core 3 將把此類(lèi)跟蹤信息轉(zhuǎn)移到實(shí)體的跟蹤信息中,讓鍵屬性只持有數(shù)據(jù)。
級(jí)聯(lián)刪除時(shí)機(jī)
在調(diào)用諸如 context.Remove() 等方法時(shí),級(jí)聯(lián)刪除將立即發(fā)生。在此之前,EF Core 在 SaveChanges 被調(diào)用之前不會(huì)計(jì)算哪些子項(xiàng)被刪除,因此很難預(yù)測(cè)到底會(huì)發(fā)生什么。該變更主要影響那些用于記錄將要修改 / 刪除哪些數(shù)據(jù)項(xiàng)日志的代碼。
可以通過(guò)將 CascadeDeleteTiming 和 DeleteOrphansTiming 選項(xiàng)設(shè)置成 CascadeTiming.OnSaveChanges 來(lái)還原以前的行為。
查詢(xún)類(lèi)型已過(guò)時(shí)
與之前版本的 Entity Framework 不同,EF Core 被設(shè)計(jì)成只能處理包含主鍵的數(shù)據(jù)表。這是有問(wèn)題的,因?yàn)橐晥D或存儲(chǔ)過(guò)程的結(jié)果沒(méi)有主鍵。所以 EF core 2.1 引入了查詢(xún)類(lèi)型的概念。
本質(zhì)上,查詢(xún)類(lèi)型使用的是并行對(duì)象模型。開(kāi)發(fā)人員使用 DbQuery?而不是 DbSet?來(lái)定義它們,使用 ModelBuilder.Query<>() 而不是 ModelBuilder.Entity<>() 來(lái)注冊(cè)它們,并使用 DbContext.Query<>() 而不是 DbContext.Set<>() 來(lái)調(diào)用它們。
許多開(kāi)發(fā)人員抱怨查詢(xún)類(lèi)型和實(shí)體類(lèi)型之間存在不必要的混淆,因此查詢(xún)類(lèi)型被移除了。從 EF Core 3 開(kāi)始,開(kāi)發(fā)人員應(yīng)該對(duì)所有數(shù)據(jù)源使用常規(guī)的 DbSet 模型。如果沒(méi)有主鍵,開(kāi)發(fā)人員在注冊(cè)實(shí)體時(shí)只需使用 .HasNoKey() 來(lái)注解它們。
忽略屬性的 Getter 和 Setter
在過(guò)去,除非要物化查詢(xún)結(jié)果,否則 EF Core 將調(diào)用屬性的 getter 或 setter 方法。在進(jìn)行查詢(xún)時(shí),如果已知屬性的支持字段,它將繞過(guò)屬性,直接寫(xiě)入底層字段。
在這個(gè)變更之后,如果已知屬性的支持字段,將始終使用底層支持字段。這樣做的好處是可以防止意外觸發(fā)業(yè)務(wù)邏輯。
缺點(diǎn)是諸如更新計(jì)算字段之類(lèi)的業(yè)務(wù)邏輯也不會(huì)被觸發(fā)。因此,我們可能需要修改 UsePropertyAccessMode 來(lái)獲得我們想要的行為。
支持字端檢測(cè)
在檢測(cè)支持字段時(shí),代碼有時(shí)候會(huì)有歧義。在過(guò)去,EF Core 只能根據(jù)內(nèi)部排名系統(tǒng)來(lái)猜測(cè)應(yīng)該設(shè)置哪個(gè)字段。
在 EF Core 3 中,任何有歧義的地方都將拋出異常。不過(guò),開(kāi)發(fā)人員必須手動(dòng)指出要使用模型生成器生成的哪個(gè)字段。
用 ValueTask 替換 Task
將 Task 作為對(duì)象被認(rèn)為是.NET 的最大錯(cuò)誤之一。雖然對(duì)于長(zhǎng)時(shí)間運(yùn)行的任務(wù)來(lái)說(shuō)是可以接受的,但當(dāng)創(chuàng)建了大量的短期任務(wù)時(shí),它常常會(huì)造成過(guò)大的內(nèi)存壓力,所以新版本引入了基于結(jié)構(gòu)的備選方案 ValueTask 。
為了支持這種新類(lèi)型,更新了 FindAsync 和 NextValueAsync 等幾個(gè)方法,讓它們返回 ValueTask 而不是 Task 。這不會(huì)影響那些等待獲取結(jié)果的代碼,但如果要對(duì)任務(wù)執(zhí)行其他操作,可能需要調(diào)用 AsTask() ,將其從 ValueTask 轉(zhuǎn)換到 Task 。
簡(jiǎn)化 IEntityType 和 IProperty
刪除了這兩個(gè)接口中的五個(gè)屬性,并用擴(kuò)展方法進(jìn)行替換。這樣做的依據(jù)是如果接口表面越小就容易實(shí)現(xiàn)。
原文地址:https://www.infoq.cn/article/jWDSt47Xu-FRdIEoRIuM
.NET社區(qū)新聞,深度好文,歡迎訪問(wèn)公眾號(hào)文章匯總?http://www.csharpkit.com?
總結(jié)
以上是生活随笔為你收集整理的EF Core 3 的 40 个中断性变更的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: .NET项目迁移到.NET Core操作
- 下一篇: 联手微软,Docker公司将推出Dock