上节咱们留了一个问题,为何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)以后的:
..上面翻译过来的大概意思就是:咱们原来考虑会加入的功能,可是如今并无进展,基本要推迟的特色.(..总结三个字,然并卵)
Database.Log
from EF6.x). We also want a simple way to view everything being logged.Database.Log 这样...()
还有一个比较有趣的东西以下:
在High priority features(高度优先的功能)中还有一段话:
我以为这个有点相似于EF6.x的IDbCommandInterceptor.
感兴趣的朋友能够去了解一下,我以前的博文也有介绍:
EntityFramework的多种记录日志方式,记录错误并分析执行时间过长缘由(系列4)
好了,就说这么多.