您的位置:首页 > 其它

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

2017-05-17 08:11 459 查看
前言

上节我们留了一个问题,为什么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.

相关文章:

一步步学习EF Core(1.DBFirst)


原文地址:http://www.cnblogs.com/GuZhenYin/p/6862505.html
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: