• 一步步学习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},
     执行消耗时间:{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)

     

    好了,就说这么多.

  • 相关阅读:
    virtual box 下安装centos 7
    java多线程通信
    redis 实现发布订阅的功能
    Ubuntu系统下为IDEA创建启动图标
    Windows玩转Docker(二):运行whalesay image
    Windows玩转Docker(一):安装
    yarn安装部署
    Hadoop yarn配置参数
    yarn的初步理解
    使用QJM部署HDFS HA集群
  • 原文地址:https://www.cnblogs.com/GuZhenYin/p/6862505.html
Copyright © 2020-2023  润新知