一步步學習EF Core(2.事務與日誌)

前言

上節咱們留了一個問題,爲何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)以後的:

..上面翻譯過來的大概意思就是:咱們原來考慮會加入的功能,可是如今並無進展,基本要推遲的特色.(..總結三個字,然並卵)

  • Simple Logging API (#1199) - We want a simple way to log the SQL being executed (like Database.Log from EF6.x). We also want a simple way to view everything being logged.
  • 嗯..翻譯過來的意思就是..咱們想提供一個更簡單的日誌記錄,好比像EF6.x中的 Database.Log 這樣...()

 

還有一個比較有趣的東西以下:

在High priority features(高度優先的功能)中還有一段話:

  • Simple command interception provides an easy way to read/write commands before/after they are sent to the database.
  • 簡單的命令攔截,將提供在發送到數據庫以前/以後讀取/寫入命令的簡單方法

我以爲這個有點相似於EF6.x的IDbCommandInterceptor.

感興趣的朋友能夠去了解一下,我以前的博文也有介紹:

EntityFramework的多種記錄日誌方式,記錄錯誤並分析執行時間過長緣由(系列4)

 

好了,就說這麼多.

相關文章
相關標籤/搜索