gpt4 book ai didi

c# - EF Core 中的多个 Includes()

转载 作者:可可西里 更新时间:2023-11-01 02:59:37 40 4
gpt4 key购买 nike

我有一个扩展方法,可以让您在 EF 中普遍包含数据:

public static IQueryable<T> IncludeMultiple<T>(this IQueryable<T> query, params Expression<Func<T, object>>[] includes)
where T : class
{
if (includes != null)
{
query = includes.Aggregate(query, (current, include) => current.Include(include));
}
return query;
}

这允许我在我的存储库中有这样的方法:

public Patient GetById(int id, params Expression<Func<Patient, object>>[] includes)
{
return context.Patients
.IncludeMultiple(includes)
.FirstOrDefault(x => x.PatientId == id);
}

我相信扩展方法在 EF Core 之前有效,但现在包括“子项”是这样完成的:

var blogs = context.Blogs
.Include(blog => blog.Posts)
.ThenInclude(post => post.Author);

有没有办法改变我的通用扩展方法以支持 EF Core 的新 ThenInclude() 实践?

最佳答案

comments 中所述通过其他,你可以采取EF6 code解析您的表达式并应用相关的 Include/ThenInclude电话。毕竟它看起来并不难,但由于这不是我的想法,我宁愿不为它的代码提供答案。

您可以改为更改您的模式以公开一些接口(interface),允许您从调用者指定您的包含而不让它访问底层可查询。

这会导致类似的结果:

using YourProject.ExtensionNamespace;

// ...

patientRepository.GetById(0, ip => ip
.Include(p => p.Addresses)
.ThenInclude(a=> a.Country));

using on 命名空间必须与包含在最后一个代码块中定义的扩展方法的命名空间名称匹配。

GetById现在是:

public static Patient GetById(int id,
Func<IIncludable<Patient>, IIncludable> includes)
{
return context.Patients
.IncludeMultiple(includes)
.FirstOrDefault(x => x.EndDayID == id);
}

扩展方法IncludeMultiple :

public static IQueryable<T> IncludeMultiple<T>(this IQueryable<T> query,
Func<IIncludable<T>, IIncludable> includes)
where T : class
{
if (includes == null)
return query;

var includable = (Includable<T>)includes(new Includable<T>(query));
return includable.Input;
}

Includable类和接口(interface),它们是简单的“占位符”,其他扩展方法将在其上完成模仿 EF Include 的工作和 ThenInclude方法:

public interface IIncludable { }

public interface IIncludable<out TEntity> : IIncludable { }

public interface IIncludable<out TEntity, out TProperty> : IIncludable<TEntity> { }

internal class Includable<TEntity> : IIncludable<TEntity> where TEntity : class
{
internal IQueryable<TEntity> Input { get; }

internal Includable(IQueryable<TEntity> queryable)
{
// C# 7 syntax, just rewrite it "old style" if you do not have Visual Studio 2017
Input = queryable ?? throw new ArgumentNullException(nameof(queryable));
}
}

internal class Includable<TEntity, TProperty> :
Includable<TEntity>, IIncludable<TEntity, TProperty>
where TEntity : class
{
internal IIncludableQueryable<TEntity, TProperty> IncludableInput { get; }

internal Includable(IIncludableQueryable<TEntity, TProperty> queryable) :
base(queryable)
{
IncludableInput = queryable;
}
}

IIncludable扩展方法:

using Microsoft.EntityFrameworkCore;

// others using ommitted

namespace YourProject.ExtensionNamespace
{
public static class IncludableExtensions
{
public static IIncludable<TEntity, TProperty> Include<TEntity, TProperty>(
this IIncludable<TEntity> includes,
Expression<Func<TEntity, TProperty>> propertySelector)
where TEntity : class
{
var result = ((Includable<TEntity>)includes).Input
.Include(propertySelector);
return new Includable<TEntity, TProperty>(result);
}

public static IIncludable<TEntity, TOtherProperty>
ThenInclude<TEntity, TOtherProperty, TProperty>(
this IIncludable<TEntity, TProperty> includes,
Expression<Func<TProperty, TOtherProperty>> propertySelector)
where TEntity : class
{
var result = ((Includable<TEntity, TProperty>)includes)
.IncludableInput.ThenInclude(propertySelector);
return new Includable<TEntity, TOtherProperty>(result);
}

public static IIncludable<TEntity, TOtherProperty>
ThenInclude<TEntity, TOtherProperty, TProperty>(
this IIncludable<TEntity, IEnumerable<TProperty>> includes,
Expression<Func<TProperty, TOtherProperty>> propertySelector)
where TEntity : class
{
var result = ((Includable<TEntity, IEnumerable<TProperty>>)includes)
.IncludableInput.ThenInclude(propertySelector);
return new Includable<TEntity, TOtherProperty>(result);
}
}
}

IIncludable<TEntity, TProperty>几乎像IIncludableQueryable<TEntity, TProperty>来自 EF,但它不扩展 IQueryable并且不允许 reshape 查询。

当然如果调用者在同一个程序集中,它仍然可以转换IIncludable。至 Includable并开始摆弄可查询的。但是好吧,如果有人想弄错,我们没有办法阻止他这样做(反射允许任何事情)。重要的是暴露的合约。

现在如果你不关心暴露 IQueryable给来电者(我怀疑),显然只是改变你的 params Func<Queryable<T>, Queryable<T>> addIncludes 的参数参数,并避免对上述所有内容进行编码。

最后最好的是:我没有测试过这个,我目前不使用 Entity Framework!

关于c# - EF Core 中的多个 Includes(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42904414/

40 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com