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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

临时表的软更新

發布時間:2023/12/4 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 临时表的软更新 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

當今絕大多數開發者都使用經典關系數據庫來存儲數據。盡管取而代之的無架構數據存儲(統稱為“NoSQL 存儲”)在各種業務方案中都證明相當有效,但經典關系數據庫是沿用了幾十年且目前仍適用的方法。每次更新現有表記錄時,都不會自動保存舊狀態。雖然目前替代現有數據尚不是各家公司需要面臨的一大難題,但事態瞬息萬變。如今,數據是每家公司的最寶貴資產,也是商業智能輸入。


在本專欄的 2016 年 5 月和 6 月刊文章(網址分別為?msdn.com/magazine/mt703431?和?msdn.com/magazine/mt707524)中,我介紹了一種常規用途方法,即通過軟更新和刪除來提升創建、讀取、更新和刪除 (CRUD) 系統。軟更新是一種標準更新操作,通過某種方式保留記錄舊狀態的做法除外。這樣一來,就會有額外 API 來檢索在系統生存期內創建的每個實體的歷史記錄。


能夠解決更新和刪除記錄,同時保留記錄舊狀態這一問題的方法不是太多。對于刪除操作,這意味著添加額外一列(通常是布爾列)將記錄標記為已刪除。對于更新操作,最實用的方法是單獨創建和維護與跟蹤相關的每個記錄的歷史記錄表。為了讓數據和歷史記錄表保持同步,需要使用其他業務和數據訪問邏輯,以及用于查詢歷史記錄的專用 API。


ANSI SQL 2011 標準已確定如何管理關系表中的歷史記錄數據。最新版 SQL Server 支持一項稱為臨時表的功能,可方便你創建和管理每個選定數據表的影子歷史記錄表。在本月的這期專欄中,我將深入探討 SQL Server 2016 臨時表及其在實體框架 (EF) 中的應用。


臨時表的結構

從概念上來講,臨時數據庫與數據庫的主要區別在于,經典數據庫僅存儲當前最新的數據。相反,臨時數據庫維護各個數據的多個副本。臨時表追加了額外幾個時間列來指明記錄何時處于給定狀態。圖 1?展示了 SQL Server 2016 Management Studio 中的臨時表。

?

圖 1:SQL Server 2016 中的臨時表


圖中有幾個值得注意的地方。一個是 dbo.BookingsHistory 子歷史記錄表。每當處理用于創建臨時表的 T-SQL 指令時,SQL Server 都會自動創建此表。開發者對歷史記錄表只有讀取權限。圖 1?中另一個值得注意的地方是,選定表的上下文菜單中沒有刪除命令。對已創建的臨時表進一步執行的所有操作都被嚴格控制,在某些情況下還是受限的,無論操作是通過 SQL Server Management Studio 界面執行,還是以編程方式執行。例如,無法刪除或復制臨時表,級聯更新和刪除也存在限制。若要詳細了解影響 SQL Server 2016 臨時表的限制,請訪問?bit.ly/2iahP1n


在 SQL Server 2016 中,可以在 CREATE TABLE 指令的末尾使用特殊子句創建臨時表。臨時表的狀態歸結起來就是啟用和禁用新 SYSTEM_VERSIONING 設置的值。換言之,可以編程方式將所有表都轉換成臨時表,然后隨時恢復原來的非臨時狀態。之前提到的影響臨時表的所有限制在 SYSTEM_VERSIONING 設置遭到禁用后不復存在。


臨時表和實體框架

當前許多開發者通過 EF 和(尤其是)EF Code First 服務來使用 SQL Server。然而,EF 暫未提供任何特殊的臨時表支持。將在不久的將來提供臨時支持。值得慶幸的是,EF 6.x 當前版本仍能提供一些對臨時表的基本支持,EF Core 提供的支持更多。不幸的是,實際上只有通過對框架進行低級別的更改,才能實現與 LINQ-to-Entities 的完全集成,尤其是 LINQ-to-Entities 提供程序生成查詢 SQL 代碼的方式。如果你是 SQL 開發者,最新的 T-SQL 語言提供了操作臨時表所需的全部語法工具。


對于 EF 開發者,最先進的臨時表可以總結如下: 首先,在 Code First 中創建臨時表非常容易。其次,可以通過 EF 按常規方式執行更新和刪除操作。第三,需要創建臨時設施,才能執行查詢。


我發現最有效的臨時表查詢方法是根據 ADO.NET 代碼使用一小組臨時存儲庫方法。這乍一聽可能會令人詫異,但到了最后,如果需要臨時表,很有可能還是最需要獲得某個特定實體的歷史記錄。例如,獲得訂單或發票的所有更改。


因此,說到底還是只需便捷專用且直接為聚合公開的 FirstOrDefault-like 方法。并且我認為存儲庫類就是很好的容器。


啟用臨時表的初始化表達式

在 EF Code First 中,只要數據庫不存在且 DbContext 類繼承自 CreateDatabaseIfNotExists,就會創建新的數據庫。這樣一來,可以為每個聲明的 DbSet 屬性新建一個表。能否同時創建臨時表? 目前,如果不使用臨時屬性和語法功能,可以執行兩步操作來創建臨時表。第一步,必須創建常規表;這其實是 Code First 通常所執行的操作。第二步,啟用 SYSTEM_VERSIONING 設置。這需要使用臨時 ALTER TABLE 語句。圖 2?展示了初始化表達式類的 Seed 方法的可能實現,用于先檢查基礎 SQL Server 的版本,然后更改以前創建的 Booking 表的狀態。?


圖 2:通過 Code First 創建臨時表


protected override void Seed(DbContext context) {// Grab the SQL Server version number? var data = context.Database.SqlQuery<string>(@"select ? left(cast(serverproperty('productversion') ?????? as varchar), 4)").FirstOrDefault();if (data != null){var version = data.ToInt();+if (version < 13)throw new Exception("Invalid version of SQL Server");}// Prepare the SQL to turn system versioning on SQL Server 2016? var cmd = String.Format(SqlSystemVersionedDbFormat, "Bookings");context.Database.ExecuteSqlCommand(cmd); }



圖 3?展示了創建臨時表所需的實際 T-SQL 命令(或 SQL Server 2016 術語中引用的帶有系統版本的表)。


圖 3:創建臨時表


private const string SqlSystemVersionedDbFormat =@"ALTER TABLE dbo.{0} ??? ADD SysStartTime datetime2(0) ??? GENERATED ALWAYS AS ROW START HIDDEN CONSTRAINT ????? DF_{0}_SysStart DEFAULT SYSUTCDATETIME(), ??? SysEndTime datetime2(0) ??? GENERATED ALWAYS AS ROW END HIDDEN CONSTRAINT ????? DF_{0}_SysEnd DEFAULT CONVERT(datetime2 (0), ????? '9999-12-31 23:59:59'), ??? PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime) ? ALTER TABLE dbo.{0} ??? SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.{0}History))";



圖 3?字符串中的 {0} 占位符指的是實際表的名稱。表名稱為 Booking,如圖 1?所示。

生成的歷史記錄表是主表的副本,外加一對名為 SysStartTime 和 SysEndTime 的 datetime2 列。總體來說,這兩列指明了記錄的特定狀態的有效期。SysStartTime 指明記錄何時處于給定狀態,SysEndTime 指明狀態的有效期何時終止。更新和刪除是導致 SysStartTime 和 SysEndTime 值發生變化的數據庫操作。


更新和刪除

SQL Server 2016 數據庫引擎支持不斷同步主表及其歷史記錄的邏輯。無論你如何執行更新,只要主表中的記錄有所更新,都會新建歷史記錄。換言之,無論是直接在 Management Studio 中編輯臨時記錄的值,還是通過存儲過程、ADO.NET 命令或 EF 進行編輯,都會新建歷史記錄,如圖 4?所示。

圖 4:更新臨時表中的記錄


圖 4?中的第一個查詢表示 ID 為 2 的記錄的當前狀態。相反,第二個查詢表示在歷史記錄表中找到的 ID 相同的記錄。此類可觀測的狀態是由我直接在 Management Studio 編輯器中執行的兩次快速更新決定的。我先將“工時”列的值從 9 更改為 13,然后在幾秒鐘后,又將“所有者”列的值從 Dino 更改為 Paul。歷史記錄表中的第一條記錄表明,最初創建的記錄(我通過 EF 以及調用 SaveChanges 在表中創建)在約五分鐘內處于有效狀態。然后,記錄處于另一種狀態幾秒鐘,最終處于當前狀態。如你所見,當前狀態沒有存儲在歷史記錄表中。圖 5?展示了在刪除 ID 為 2 的記錄后表的狀態。


圖 5:刪除臨時表中的記錄


查詢 ID 為 2 的記錄時,主表返回空結果集。而現在歷史記錄表有第三條記錄,從上次更新到執行刪除時有效。


查詢特定實體

跟蹤所有狀態更改非常有用,因為這樣就不會錯過系統中發生的任何一件事。你可以查看所有數據庫操作的完整(和可用)日志。更棒的是,這樣可以生成狀態更改的完整列表,這具有比 SQL 語句的普通日志更為相關的業務角色。換言之,從概念上來說,臨時表非常接近事件溯源;我敢說,臨時表是基于 CRUD 的事件溯源形式。讓我們來看看如何查詢給定聚合的過往狀態。


盡管歷史記錄嵌套表就能夠進行查詢,但 SQL Server 2016 仍提供了用于查詢給定記錄的臨時數據的直接語法。下面展示了用于在給定時間間隔內檢索 ID 為 2 的記錄版本的示例命令架構:


var sql = @"SELECT * FROM Bookings? ? FOR SYSTEM_TIME BETWEEN '{0}' AND '{1}' ? WHERE ID=2";


臨時表是常規查詢,外加設置要考慮的時間間隔的 FOR SYSTEM_TIME 子句。數據庫引擎會通過查看歷史記錄表中的其他列以及主表和嵌套表的內容來解析查詢。查詢應返回記錄列表。如何強制 EF 像這樣運行查詢? 在 EF 6 中,只能利用 DbSet 類的 SqlQuery 方法:


using (var db = new EF6Context()) {var current = db.Bookings.Single(b => b.Id == 1);var time = DateTime.Now.AddMinutes(-5);var old = db.Bookings.SqlQuery("SELECT * FROM dbo.BookingsFOR SYSTEM_TIME AS OF {0} WHERE Id = 1", time).SingleOrDefault(); }


請注意,對于 EF 6,查詢中返回的列名必須與類中的屬性名匹配。這是因為 SqlQuery 不使用映射。如果列名和屬性名不匹配,需要在 SELECT 列表中為列指定別名,而不直接使用 SELECT *。


使用 EF Core,在某些方面操作會變得更為簡單。在 EF Core 中,使用的方法是 FromSql。首先,FromSql 方法使用映射;也就是說,如果列名和屬性名不匹配,也不用擔心要指定別名:


using (var db = new EFCoreContext()) {var current = db.Bookings.Single(b => b.Id == 1);var time = DateTime.Now.AddMinutes(-5);var old = db.Bookings.FromSql("SELECT * FROM dbo.BookingsFOR SYSTEM_TIME AS OF {0}", time).SingleOrDefault(b => b.Id == 1); }


其次,可以使用 LINQ 在初始選擇的基礎上進行撰寫。也就是說,可以使用 Where、OrderBy、GroupBy 或其他任何 LINQ 運算符,這些運算符通常會轉換成窗體查詢:


SELECT projection FROM (SELECT * FROM dbo.Bookings FOR SYSTEM_TIME AS OF {0}) as Bookings WHERE condition


盡管如此,如果你愿意,可以始終使用普通 ADO.NET 和數據讀取器來訪問臨時表中存儲的數據。


總結

當然可以在大部分基于 EF 的數據層中使用臨時表,即使偶爾使用普通 ADO.NET 進行查詢,也可以利用 LINQ-to-Objects 提高內存復雜度。實體框架團隊路線圖表明,在接下來的幾個月里,要對臨時表實施一些工作項。那么,讓我們拭目以待吧。



Dino Esposito?是《Microsoft .NET: 構建面向企業的應用程序》(Microsoft Press,2014 年)和《使用 ASP.NET 構建新型 Web 應用程序》(Microsoft Press,2016 年)的作者。Esposito 是 JetBrains 公司 .NET 和 Android 平臺的技術推廣專家,經常在全球性行業活動上發表演講,他在?software2cents.wordpress.com?和Twitter:?@despos.上分享了他的軟件構想。


衷心感謝以下 Microsoft 技術專家對本文的審閱:?Rowan Miller

原文地址:https://msdn.microsoft.com/en-us/magazine/mt795184


.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注

總結

以上是生活随笔為你收集整理的临时表的软更新的全部內容,希望文章能夠幫你解決所遇到的問題。

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