英文:
Parameterizing ThenInclude() in Entity Framework
问题
我已经创建了一种设置我的 EF 查询的方法,通过传递参数来使用 Include()
。
public static class AppUserExtensions
{
public static IQueryable<AppUser> FindById(this IQueryable<AppUser> source, int userId, Expression<Func<AppUser, object?>>[] includes)
{
var query = source.Where(u => u.Id == userId);
foreach (var include in includes)
query = query.Include(include);
return query;
}
}
public static class AppUserIncludes
{
public static Expression<Func<AppUser, object?>>[] Organizations => new Expression<Func<AppUser, object?>>[]
{
u => u.Campaigns,
u => u.Cantons,
u => u.States,
u => u.Countries,
};
}
这种方法的优点是我避免了在代码中散布的冗长查询,而是拥有了一组适用于任何类型的搜索的查询,以及一组用于选择要包含的属性的数组。我可以使用任何数组与任何查询。
但是... 我现在也面临着对 ThenInclude()
的相同问题。
我想要的是一种类似于构建数组的对象(我知道我在这里写的不是有效的):
Complex<T1, T2> Expression<Expression<Func<T1, object?>>, Expression<Func<T2, object?>>[]>
我在如何做到这一点方面遇到了困难。但我想要能够创建一些东西,其中我传递:
<AppUser, Campaign>(u => u.Campaigns, CampaignExtensions.Parents)
然后在查询中我可以做类似的事情:
foreach (var thenInclude in thenIncludes)
query = query.Include(include).ThenInclude(thenInclude);
我知道我可能没有完美地解释这一点,因为我不确定如何实现这一点,这就是为什么我在询问。我希望这足够让某人可以帮助我。有办法做到这一点吗?
另外,我假设最终查询中可能会有相同的 Include(u => u.Campaigns)
出现3次或5次没有什么坏处。SQL Server 会将其减少为相同的 SQL,因为它会解析所有表达式吗?
进一步的思考。如果我按照如下方式调用 Include()
,它会返回一个知道自己正在返回一个集合的类型:
IIncludableQueryable<Campaign, ICollection<AppUser>> x = query.Include(campaign => campaign.Followers!);
所以在这种情况下,T1 是 AppUser,它返回一个对象,该对象知道 Campaign 需要成为 T2 的类型。因此,如果有一种方法可以在代码中知道这一点,以便在编写代码时进行类型检查,那将是最理想的情况。
所有的信息都在那里,所以我猜这是可能的。我为 C# 和泛型添加了标签,因为这可能更多是一个关于泛型的问题,而不是 EF 的问题。
英文:
I've created a way to set up my EF queries to take what gets Include()
via passing a parameter.
public static class AppUserExtensions
{
public static IQueryable<AppUser> FindById(this IQueryable<AppUser> source, int userId, Expression<Func<AppUser, object?>>[] includes)
{
var query = source.Where(u => u.Id == userId);
foreach (var include in includes)
query = query.Include(include);
return query;
}
}
public static class AppUserIncludes
{
public static Expression<Func<AppUser, object?>>[] Organizations => new Expression<Func<AppUser, object?>>[]
{
u => u.Campaigns,
u => u.Cantons,
u => u.States,
u => u.Countries,
};
}
The beauty of this approach is I avoid long queries strewn throughout my code and instead have a set of queries for any kind of search and then this set of arrays to select which properties to Include(). And I can use any array with any query.
But... I'm now facing the same issue for ThenInclude()
.
What I want is some kind of object to build an array of like (what I'm writing here I know is not valid):
Complex<T1, T2> Expression<Expression<Func<T1, object?>>, Expression<Func<T2, object?>>[]>
I'm struggling with exactly what/how to do this. But I want to be able to create something where I pass:
<AppUser, Campaign>(u => u.Campaigns, CampaignExtensions.Parents)
And then in the query I can do something like:
foreach (var thenInclude in thenIncludes)
query = query.Include(include).ThenInclude(thenInclude);
I know I may not be explaining this perfectly as I'm not sure how to accomplish this and that's why I'm asking. I hope this is enough that someone can help. Is there a way to do this?
Also, I assume there's no downside to the eventual query possibly having the same Include(u => u.Campaigns)
in ot 3 or 5 times. Doesn't SQL Server reduce this down to the same SQL as it figures out all the expressions?
Further thought. If I call Include() as follows, it returns a type that knows what type it is returning a collection of:
IIncludableQueryable<Campaign, ICollection<AppUser>> x = query.Include(campaign => campaign.Followers!);
So where T1 in this case is AppUser, it returns an object that knows Campaign needs to be the type for T2. So if there's a way to know that in the code so it is type checking as I write it, and at compile time, that would be optimal.
The information is all there so I'm guessing this is possible. I added tags for C# & generics because this may be more a generics question and not so much an EF question.
答案1
得分: 0
看起来你应该能够使用路径来实现这个功能,路径是一个用点号分隔的相关对象列表,可以在查询结果中返回。
示例:Include("Addresses.StateProvince.CountryRegion")
英文:
Seems you should be able to do this with path The dot-separated list of related objects to return in the query results.
Example Include("Addresses.StateProvince.CountryRegion")
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论