一步步学习EF Core(2.事务与日志)

前言

上节我们留了一个问题,为什么EF Core中,我们加载班级,数据并不会出来

其实答案很简单,~ 因为在EF Core1.1.2 中我们在EF6.0+中用到的的延迟加载功能并没有被加入,不过在EF Core 2.0中,这个功能将回归

而且这个功能是否需要被加入进去,社区也在激烈的讨论当中,有兴趣的可以去看看:

https://github.com/aspnet/EntityFramework/issues/3797

那么我们该如何加载关联的班级呢?.

直接通过Linq join当然是可以的. 我们也可以通过贪婪加载来获取,修改查询代码如下:

 public IActionResult ListView()
        {
            return View(_context.UserTable.Include(a=>a.Class).ToList());
        }

效果如下:

下面我们开始今天的内容

事务

关于EF Core的事务,其实与EF 6.x几乎一样,代码如下:

            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即可回滚,我这里的写法,其实有点无耻.

不过目的是告诉大家,要在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)

好了,就说这么多.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏NetCore

[原创]Fluent NHibernate之旅(四)-- 关系(上)

经过了前面三篇的介绍,相信大家对Fluent NHibernate已经有一定的了解了,在我们学习中,Fluent 也已经进入了RTM版本。这次的版本发布离RC版...

22960
来自专栏王大锤

再谈RunLoop

30340
来自专栏GuZhenYin

浅析Entity Framework Core2.0的日志记录与动态查询条件

前言 Entity Framework Core 2.0更新也已经有一段时间了,园子里也有不少的文章.. 本文主要是浅析一下Entity Framework C...

34360
来自专栏deepcc

linux中nodejs后台运行工具forever

33980
来自专栏Java架构师历程

Struts2的工作原理

在学习struts2之前,首先我们要明白使用struts2的目的是什么?它能给我们带来什么样的好处?

11340
来自专栏JAVA高级架构

分布式之延时任务方案解析

13820
来自专栏Hadoop实操

如何使用HBase存储图片

61820
来自专栏DannyHoo的专栏

iOS开发中在指定的某些线程执行完之后去执行其他线程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details/...

14530
来自专栏程序员互动联盟

Windows SDK编程基本框架

在Windows平台下,最常见最流行的编程就是MFC编程了,在网上可以搜索出大把的MFC编程相关的文章,今天我们来讨论另外一种windows下的编程模式,即W...

344130
来自专栏跟着阿笨一起玩NET

在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。

本文转载:http://blog.csdn.net/playing9c/article/details/7471918

66710

扫码关注云+社区

领取腾讯云代金券