一步步学习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 条评论
登录 后参与评论

相关文章

来自专栏互联网技术栈

Spring Boot集成Mybatis

Spring Boot集成Mybatis的配置方式有很多种,可以使用mybatis-spring-boot-starter、注解方式、传统集成方式等。本文采用的...

422
来自专栏服务端思维

状态机在移动端项目中的使用

RichsJeson,曾就任于亚信科技担任 Android 端主要负责人,现就职某知名互联网公司高级软件开发工程师,花名 Jeson,目前从事 Android ...

962
来自专栏软件开发 -- 分享 互助 成长

Android log日志

LOG是用来记录程序执行过程的机制,它既可以用于程序调试,也可以用于产品运营中的事件记录。在Android系统中,提供了简单、便利的LOG机制,开发人员可以方便...

1769
来自专栏非著名程序员

浅谈Andorid开发中的MVP模式

? 导语:最近公众号后台经常收到一些消息,说能不能讲一些开发模式,经过思考后,我决定讲一讲MVP模式。希望对大家能够有所帮助。并写了一个简单的小demo。 ...

1976
来自专栏wOw的Android小站

[Android][Framework] 添加系统服务

做系统开发,有时候需要自己定义一些接口供App使用, 同时为了方便维护管理,就会需要自己建立一个服务,把新的功能集中在一起。下面就是新建一个系统服务的基本步骤。

1012
来自专栏dalaoyang

SpringBoot学习历程

经过同事介绍,听说了SpringBoot框架,并且亲身感受过这个框架的优势,经过一段时间的学习和使用,故此写博客记录自己学习SpringBoot的全部历程。

40610
来自专栏Android常用基础

应用自动更新封装-Android

应用更新应该是现在每个应用必备的一个功能。正是通过不断的更新,不断的调优,才使我们的应用更完善。当然在各大应用市场中,它们已经帮我们实现了这项功能,但是有一个问...

811
来自专栏yang0range

Activity详解(二)——异常情况下的生命周期分析

最近 无意当中看到一道面试题是关于Activity异常情况下的生命周期分析,感觉自己还有所欠缺,随即在书中寻找完整答案,特记录如下。

844
来自专栏平凡文摘

Spring Boot 内嵌容器 Tomcat / Undertow / Jetty 优雅停机实现

2282
来自专栏yang0range

Activity详解(一)——典型生命周期分析

Activity的重要性,在Android的开发当中不言而喻,作为四大组件当中,使用最为频繁的组件,有必要对它进行一个全方面的了解和认识,下面我们通过一系列的文...

902

扫码关注云+社区