上節咱們留了一個問題,爲何EF Core中,咱們加載班級,數據並不會出來html
其實答案很簡單,~ 由於在EF Core1.1.2 中咱們在EF6.0+中用到的的延遲加載功能並無被加入,不過在EF Core 2.0中,這個功能將回歸git
並且這個功能是否須要被加入進去,社區也在激烈的討論當中,有興趣的能夠去看看:github
https://github.com/aspnet/EntityFramework/issues/3797數據庫
那麼咱們該如何加載關聯的班級呢?.app
直接經過Linq join固然是能夠的. 咱們也能夠經過貪婪加載來獲取,修改查詢代碼以下:ide
public IActionResult ListView() { return View(_context.UserTable.Include(a=>a.Class).ToList()); }
效果以下:post
下面咱們開始今天的內容ui
關於EF Core的事務,其實與EF 6.x幾乎同樣,代碼以下:this
using (var tran = _context.Database.BeginTransaction()) { try { _context.ClassTable.Add(new ClassTable { ClassName = "AAAAA", ClassLevel = 2 }); _context.ClassTable.Add(new ClassTable { ClassName = "BBBBB", ClassLevel = 2 }); _context.SaveChanges(); throw new Exception("模擬異常"); tran.Commit(); } catch (Exception) { tran.Rollback(); // TODO: Handle failure } }
在異常中Rollback便可回滾,我這裏的寫法,其實有點無恥.url
不過目的是告訴你們,要在Commit以前回滾.
否則會獲得一個異常:This SqlTransaction has completed; it is no longer usable.」
下面咱們來說一下關於EF Core中的日誌
咱們知道,在ASP.NET Core中,大量的使用了IOC的手法來注入咱們所須要的類.
EF Core其實也同樣,.
首先咱們須要建立一個EF日誌類,繼承Microsoft.Extensions.Logging.ILogger
以下:
private class EFLogger : ILogger { private readonly string categoryName; public EFLogger(string categoryName) => this.categoryName = categoryName; public bool IsEnabled(LogLevel logLevel) { return true; } public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { Debug.WriteLine($"時間:{DateTime.Now.ToString("o")} 日誌級別: {logLevel} {eventId.Id} 產生的類{this.categoryName}"); DbCommandLogData data = state as DbCommandLogData; Debug.WriteLine($"SQL語句:{data.CommandText},\n 執行消耗時間:{data.ElapsedMilliseconds}"); } public IDisposable BeginScope<TState>(TState state) { return null; } }
我這裏面的Debug.WriteLine是爲了方便調試.
正常狀況下固然是寫入日誌文件,能夠用Log4Net
而後,咱們建立一個空的日誌類(用來過濾不須要記錄的日誌)以下:
private class NullLogger : ILogger { public bool IsEnabled(LogLevel logLevel) { return false; } public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { } public IDisposable BeginScope<TState>(TState state) { return null; } }
而後,咱們建立一個日誌提供類(注入用,EF Core1.0版本注意註釋),以下:
public class MyFilteredLoggerProvider : ILoggerProvider { public ILogger CreateLogger(string categoryName) { // NOTE: 這裏要注意,這是 EF Core 1.1的使用方式,若是你用的 EF Core 1.0, 就需把IRelationalCommandBuilderFactory替換成下面的類 // Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory if (categoryName == typeof(IRelationalCommandBuilderFactory).FullName) { return new EFLogger(categoryName); } return new NullLogger(); } public void Dispose() { } }
而後咱們到Startup.cs的Configure()方法中注入咱們的日誌提供類
代碼以下:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddProvider(new MyFilteredLoggerProvider()); ....省略 }
運行程序,獲得以下調試信息:
至此,咱們就完成了日誌的記錄工做.
那麼問題來了,在Asp.NET core中,咱們能夠這樣注入進行日誌記錄.
若是在別的項目(好比控制檯)中,怎麼辦?
下面就來解決這個問題.
在非Asp.NET core的程序中,咱們須要把日誌提供器從上下文裏注入以下:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); LoggerFactory loggerFactory = new LoggerFactory(); loggerFactory.AddProvider(new MyFilteredLoggerProvider()); //注入 optionsBuilder.UseLoggerFactory(loggerFactory); }
寫在最後,其實在EF Core的路線圖中,咱們能夠看到,在2.0的版本將會提供一個更簡單的日誌記錄方式
這段話是在(Features originally considered but for which we have made no progress and are essentially postponed)以後的:
..上面翻譯過來的大概意思就是:咱們原來考慮會加入的功能,可是如今並無進展,基本要推遲的特色.(..總結三個字,然並卵)
Database.Log
from EF6.x). We also want a simple way to view everything being logged.Database.Log 這樣...()
還有一個比較有趣的東西以下:
在High priority features(高度優先的功能)中還有一段話:
我以爲這個有點相似於EF6.x的IDbCommandInterceptor.
感興趣的朋友能夠去了解一下,我以前的博文也有介紹:
EntityFramework的多種記錄日誌方式,記錄錯誤並分析執行時間過長緣由(系列4)
好了,就說這麼多.