以前(使用 .net 4.5.2 和 EF 6 时(。我有一个通用的Get
方法,它接受了一些包含,如下所示;
public abstract class DataContext : IdentityDbContext<ApplicationUser, ApplicationRole, int>, IDataContext
{
public DataContext(DbContextOptions options)
: base(options)
{
}
// reduced for brevity
public T Get<T>(int id, params Expression<Func<T, object>>[] includes) where T : class, IEntity
{
return this.Set<T>().Include(includes).FirstOrDefault(x => x.Id == id);
}
然后我会打电话举例;
context.Get<Job>(id,
x => x.Equipment,
x => x.Equipment.Select(y => y.Type));
包括Job.Equipment
和Job.Equipment.Type
。
但是,当我将其移植到 asp.net 核心 2 时。我尝试了相同的通用方法,但是如果我尝试包含子实体,则会出现以下错误;
属性表达式 'x => {从 x.设备 y 中选择 [y]。类型}' 无效。表达式应表示属性访问:'t => t.MyProperty'。有关包含相关数据的详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=746393。
任何人都可以建议我如何解决此问题以将子实体包含在具有实体框架核心 2 的通用Get<T>
方法中?
更新
通过查看文档,有一个额外的包含方法
include(string navigationPropertyPath)
我添加了以下方法;
public T Get<T>(int id, string[] includes) where T : class, IEntity
{
var result = this.Set<T>().AsQueryable();
foreach(var include in includes)
{
result = result.Include(include);
}
return result.FirstOrDefault(x => x.Id == id);
}
哪个确实有效,尽管我不相信这里的效率?
EF CoreInclude
/ThenInclude
模式不能像 EF6 中那样用Expression<Func<T, object>>[]
表示。
查看其中一个EF Core扩展的源代码 - Microsoft.EntityFrameworkCore.UnitOfWork,它声称是
Microsoft.EntityFrameworkCore 的插件,支持存储库、工作单元模式和支持分布式事务的多个数据库。
看起来包含的预期模式应该基于Func<IQueryable<T>, IIncludableQueryable<T, object>>
:
public T Get<T>(int id, Func<IQueryable<T>, IIncludableQueryable<T, object>> include = null) where T : class, IEntity
{
var result = this.Set<T>().AsQueryable();
if (include != null)
result = include(result);
return result.FirstOrDefault(x => x.Id == id);
}
缺点是它增加了对调用方的 EF Core 依赖关系,并且需要using Microsoft.EntityFrameworkCore;
。在您的情况下,这不是必需的,因为您正在扩展DbContext
。
示例的用法为:
context.Get<Job>(id, q => q
.Include(x => x.Equipment)
.ThenInclude(y => y.Type));
你可以做这样的事情:
public abstract class DataContext : IdentityDbContext<ApplicationUser, ApplicationRole, int>, IDataContext
{
public DataContext(DbContextOptions options)
: base(options)
{
}
// reduced for brevity
public T Get<T>(int id, Func<IQueryable<T>, IIncludableQueryable<T, object>> includes = null) where T : class, IEntity
{
IQueryable<T> queryable = this.Set<T>();
if (includes != null)
{
queryable = includes(queryable);
}
return queryable.FirstOrDefault(x => x.Id == id);
}
}
context.Get<Job>(id, includes: source => source.Include(x => x.Equipment).ThenInclude(x => x.Type));