# Entity Framework ###### tags: `Learning` ## 重要須知 1. 在 Query 的時候,先下 Where、Select... 再去進行 Sum、Count、ToList...等的動作。IQueryable 在下 Where、Select... 時,還不會去執行 Query;Sum、Count、ToList 會去執行 Query。所以下好條件再去執行,才不會影響效能。 2. EF 的 Model 本身就有自己偷偷紀錄哪個欄位被改,所以只要取出資料並修改(ex. context.tableA.FirstOrDefault().ColumnA = "666"),改好後 SaveChange,就會將 ColumnA = "666" 改到 DB 中! --- ## ★★★接SP的回傳結果 ( EF真的屌 ) SP長這樣的  EF產出的SP的Function長這樣  EF產出的SP的Function中,有一個output參數,但Function沒定義他,於是我自己定義了傳進去。  執行完SP之後,EF將值塞入了我剛定義的參數中  --- ## Unit Of Work & Repository Unit of work = DB Repository = Table Unit of work 裡面有 Context 物件 Repository 建構子需傳入 Unit of work 物件 為了不要使用一個 table 就開一個連線 (?),但是其實用 using (Context context = new Context()) 也可以解啦 使用 Repository 來跟資料庫做連結 像是這有三個 Service 其實可以把 Repository 寫成泛型,一個檔案就能解決了  --- ## 不想用 Unit of work And Repository ``` using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted })) using (YourContext context = new YourContext()) { // Do something... // 如果有更改資料,記得 SaveChange & Complete // 如果只有 Call SP,只知道不用 SaveChange,不知道要不要 scope.Complete? // context.SaveChanges(); // scope.Complete(); } ``` --- ## EF DB Model 小技巧 每次 Entity Framework 都會重建 DB Model,每次加上的 Attribute 會被洗掉,其實你可以自己建立一個 MetaData,定義好 Attribute,透過 MetaData 取資料就可以不用怕每次都被洗掉。 --- ## 自訂驗證 Valid 特別注意自訂後端驗證,是<span style="color:red">前端驗證完之後,Post到後端進行 ModelBinding 後才會觸發</span>,所以你的 Action 必須要寫好對應要接值的參數 Model 型態,<span style="color:red">程式有需要 Binding 你剛剛自訂驗證的 Model,才會觸發自訂驗證的 Function 喔 !</span> Model 必須繼承 IValidatableObject  Function ↓  上圖的驗證是針對某個欄位的驗證,如果想要錯誤訊息寫在 ValidationSummary 的話,就不用特別傳第二個欄位的 string [] 參數(key) ※ 第二個欄位的 string [] 參數 (key) 是為了匹配 ValidationMessageFor ``` @Html.ValidationMessageFor(model => model.Document.FromOrg, "", new { @class = "text-danger" }) ``` 如下圖↓  ※ ValidationSummary 的第一個參數必須為 true (顯示模型層級的錯誤,就是非 Property 的驗證錯誤,簡單來說就是 沒有給 Key 的 Error 啦~) ``` @Html.ValidationSummary(true, "", new { @class = "text-danger" }) ``` #### 20200417 我在驗證上遇到了一些問題: > 我 return 的 ValidationResult 明明就沒有給 key,為什麼會沒顯示在顯示在模型層級錯誤的 Summary 中? > > 我的 Model 長這樣 >  > 自訂驗證寫在 tblDocument 的 Model 中 後來查發現是 ValidationResult 還是有給 Key,他給的 Key 是 "Doucument" ( 因為被 ViewModel 包起來的關係,可能微軟就覺得他不算是模型層級的錯誤,要解的話,應該是將自訂驗證寫在 ViewModel 中,我猜這樣 ValidationResult 就不會自動給 key 了) ※備註: 一般的 Attribute (Ex.Required),都是在前端進行作業,會在 Html 標籤中給驗證相關的屬性,所以並不會進到後端,所以才要自訂驗證。 --- ## Metadata & 自訂驗證方式 ※用 EF 產出的 Model 不可加上 Attribute,到時候 DB 更新 Model 重抓就會遺失 ※自訂後端驗證必須掛在原本的 Model 上 ``` [MetadataType(typeof(tblDocumentsMeta))] public partial class tblDocuments : IValidatableObject { internal sealed class tblDocumentsMeta { [DisplayName("收文編號")] public string DocumentID { get; set; } [Required(ErrorMessage = "收文日期 為必填 !")] [DisplayName("收文日期")] [DisplayFormat(DataFormatString = "{0:yyyy/MM/dd}", ApplyFormatInEditMode = true)] public System.DateTime DocumentDate { get; set; } public bool IsReceived { get; set; } [Required(ErrorMessage = "主旨 為必填 !")] [DisplayName("主旨")] [StringLength(200, ErrorMessage = "最多只能填 200 個字 !")] public string Subject { get; set; } [DisplayName("內容")] public string Content { get; set; } [Required(ErrorMessage = "來文單位 為必填 !")] [DisplayName("來文單位")] public string FromOrg { get; set; } [Required(ErrorMessage = "來文字號 為必填 !")] [DisplayName("來文字號")] public string FromID { get; set; } [Required(ErrorMessage = "來文日期 為必填 !")] [DisplayName("來文日期")] [DisplayFormat(DataFormatString = "{0:yyyy/MM/dd}", ApplyFormatInEditMode = true)] public Nullable<System.DateTime> FromDate { get; set; } [Required(ErrorMessage = "類別 為必填 !")] [DisplayName("類別")] public Nullable<int> Class { get; set; } [Required(ErrorMessage = "等級 為必填 !")] [DisplayName("等級")] public string Level { get; set; } [Required(ErrorMessage = "歸屬單位 為必填 !")] [DisplayName("歸屬單位")] public string DepartmentTo { get; set; } [DisplayName("DepartmentFrom")] public string DepartmentFrom { get; set; } [DisplayName("承辦人")] public string CaseOfficer { get; set; } public bool UseStatus { get; set; } } #region Validate public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { var data = new HRContext().tblDocuments.ToList(); // 檢查使用者填入的來文單位、來文日期、來文單號在資料庫裏面不得重複,否則顯示錯誤提示 if (data.Any(x => x.FromOrg == FromOrg && x.FromDate == FromDate && x.FromID == FromID)) yield return new ValidationResult($"來文單位: {FromOrg}、來文日期: {FromDate.Value.ToString("yyyy/MM/dd")}、來文單號: {FromID},已存在", new string[] { "FromOrg" }); } #endregion } ``` --- ## 使用 AsNoTracking 使用 AsNoTracking 的話,會 always 讀取最新資料,不會從 DB 的 Cache 取得資料。 ``` return _Context.Employees.AsNoTracking().ToList(); ``` --- ## ProxyCreationEnabled 會建立一個動態的 Class,其中裡面還是包含實體的 Model 連結 ``` _Context.Configuration.ProxyCreationEnabled = true; ``` --- ## 將結果顯示在 "輸出" 視窗中 ``` _Context.Database.Log = s => Debug.WriteLine(s); ```   --- ## TransactionScope 出現了 基礎提供者在 Open 失敗 !! ``` using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted })) using (HRContext context = new HRContext()) { // Do context 相關的操作... ( EF 的連線 ) // Do Service 相關的操作... ( unitOfwork 的連線 ) } ``` 這時候就會是兩條連線 => 分散式交易 需要特別處理 ( 尚未知道怎麼處理 ) ---
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up