正如comments所說的那樣,您可以帶上EF6 code來解析您的表達式並應用相關的Include
/ThenInclude
調用。它畢竟看起來不那麼辛苦,但由於這不是我的想法,所以我寧願不用代碼來回答它。
你可以改變你的模式來公開一些接口,允許你從調用者指定你的包含而不讓它訪問基礎查詢。
這將導致類似的信息(在using
名稱空間必須與命名空間名稱包含在最後的代碼塊下面定義的擴展方法一致):
using YourProject.ExtensionNamespace;
// ...
patientRepository.GetById(0, ip => ip
.Include(p => p.Addresses)
.ThenInclude(a=> a.Country));
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;
}
現在IncludeProvider
類&接口,這是簡單的 「佔位符」 上附加擴展方法是不行的模仿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>
與EF幾乎相同,但不會延長IQueryable
,並且不允許重新塑造查詢。
當然,如果調用者在同一個程序集中,它仍然可以將IIncludable
投射到Includable
並開始擺弄查詢。但是,如果有人想弄錯它,我們不可能阻止他這樣做(反射允許任何事情)。重要的是合同。
現在,如果你不在乎暴露IQueryable
給調用者(我懷疑),顯然只是改變你的params
論點的論據Func<Queryable<T>, Queryable<T>> addIncludes
,避免編碼上述所有這些事情。
而最好的結局:我沒有測試過這個,我目前沒有使用實體框架!
只是做' .include(include)'爲你的數組中的第一個表達式,'current.ThenInclude(include)'爲剩餘的? – Evk
@Evk你正在傳遞一個Linq表達式到這個擴展方法中,所以輸入是這樣的:'x => x.Posts.Select(p => p.Author)''。 – im1dermike
我明白你的意思了。您是否測試過舊的語法在EF Core中無效?我聽說過它,但沒有測試自己。 – Evk