Entity Framework: смешанные предикаты смешанных объектов
Извините за мой ужасный английский.
Я пытаюсь расширить мою модель EF (с LinqKit).
Пока я работаю с выражениями из отдельных сущностей, у меня нет никаких проблем, но если я хочу работать со смешанными выражениями, я просто застреваю.
Например, что-то вроде почтового класса...
partial class vit_post
{
//[...]
public static Expression<Func<vit_post, bool>> HasMetas(IEnumerable<MetaFilter> metaArgs)
{
var resultsInner = PredicateBuilder.True<vit_post>();
resultsInner.And(p=>p.vit_postmeta.Any(pm => (pm.hide == false)));
foreach (var metaArg in metaArgs)
{
var mf = metaArg;
resultsInner.And(p=>p.vit_postmeta.Any(pm => (pm.meta_key == mf.MetaKey && mf.Compare(pm.meta_value))));
if (mf.ChildrenMetaFilters != null)
{
Expression<Func<vit_post, bool>> resultsInner2;
switch (mf.LogicalOperator)
{
case LogicalOperators.AND:
resultsInner2 = PredicateBuilder.True<vit_post>();
resultsInner = resultsInner2.And(HasMetas(mf.ChildrenMetaFilters));
break;
case LogicalOperators.OR:
resultsInner2 = PredicateBuilder.False<vit_post>();
resultsInner = resultsInner2.Or(HasMetas(mf.ChildrenMetaFilters));
break;
}
}
}
return resultsInner;
}
//[...]
}
... расширяет сущность "vit_post" с помощью выражения HasMetas.
Используя этот фрагмент, я получаю подмножество сущностей, как и ожидалось:
public SearchResults GetResults()
{
var query = dbc.vit_posts.AsExpandable();
//[...]
if (SearchArgs.Metas != null)
{
var postsbycontent = vit_post.HasMetas(SearchArgs.Metas);
outer = Data.Utility.And(outer, postsbycontent);
}
//[...]
query = query.Where(outer);
var searchResults = new SearchResults
{
Items = searchResultsItems
};
return searchResults;
}
Но если я попытаюсь переместить это выражение в сущность "vit_postmeta" следующим образом:
partial class vit_postmeta
{
//[...]
var resultsInner = PredicateBuilder.True<vit_postmeta>();
resultsInner.And(pm => (pm.hide == false));
foreach (var metaArg in metaArgs)
{
var mf = metaArg;
resultsInner.And(pm => (pm.meta_key == mf.MetaKey && mf.Compare(pm.meta_value)));
if (mf.ChildrenMetaFilters != null)
{
Expression<Func<vit_postmeta, bool>> resultsInner2;
switch (mf.LogicalOperator)
{
case LogicalOperators.AND:
resultsInner2 = PredicateBuilder.True<vit_postmeta>();
resultsInner = resultsInner2.And(HasMetas(mf.ChildrenMetaFilters));
break;
case LogicalOperators.OR:
resultsInner2 = PredicateBuilder.False<vit_postmeta>();
resultsInner = resultsInner2.Or(HasMetas(mf.ChildrenMetaFilters));
break;
}
}
}
return resultsInner;
//[...]
}
Моя идея состояла в том, чтобы сохранить оригинальный метод в vit_post и изменить его следующим образом:
partial class vit_post
{
//[...]
public static Expression<Func<vit_post, bool>> HasMetas(IEnumerable<MetaFilter> metaArgs)
{
var resultsInner = PredicateBuilder.True<vit_post>();
resultsInner.And(p=>p.vit_postmeta.HasMetas(metaArgs));
return resultsInner;
}
//[...]
}
Но я не могу этого сделать, поскольку "vit_postmeta" не содержит определения для "HasMetas", и не может быть найден метод расширения "HasMetas", принимающий первый аргумент типа "vit_postmeta" ".
Я что-то упускаю, я знаю, но я не могу найти что.
ОБНОВИТЬ
Я нашел альтернативное решение (и, возможно, правильное тоже), реализующее все мое выражение в соответствующих частичных классах сущностей. Например, у vit_post есть все выражения, относящиеся к таблице vit_posts, а у vit_postmeta есть все выражения, относящиеся к таблице vit_postmeta.
Мой класс поиска имеет закрытый метод для каждой сущности. Что-то вроде:
private IQueryable<vit_post> QueryPosts()
{
IQueryable<vit_post> queryPosts = VITContext.vit_posts.AsExpandable();
Expression<Func<vit_post, bool>> outerPredicate = PredicateBuilder.True<vit_post>();
if (!_searchArgs.IncludeExpiredPosts)
{
Expression<Func<vit_post, bool>> postsByExpiration = vit_post.ExcludeExpired();
outerPredicate = Data.Utility.And(outerPredicate, postsByExpiration);
}
if (_searchArgs.LocaleCode != null)
{
Expression<Func<vit_post, bool>> postsByLanguage = vit_post.HasLocaleCode(_searchArgs.LocaleCode);
outerPredicate = Data.Utility.And(outerPredicate, postsByLanguage);
}
[...]
}
Затем функция GetResults() вызывает все эти методы и присоединяется к ним:
internal string GetResults()
{
IQueryable<vit_post> queryPosts = QueryPosts();
if (_searchArgs.Metas != null)
{
IEnumerable<vit_postmeta> queryMetas = QueryMetas();
queryPosts = from p in queryPosts
join m in queryMetas
on new {id = p.ID, loc = p.locale} equals new {id = m.post_id, loc = m.locale}
select p;
}
}
Таким образом, я могу заставить запрос работать, но я все еще не уверен, что это правильный способ сделать это.
1 ответ
Вы еще не видели / не отвечали на мой вопрос, но если vit_postmeta
а также vit_post
каким-либо образом связаны с наследованием, вы можете сделать что-то вроде:
public static Expression<Func<T, bool>> HasMetas<T>(IEnumerable<MetaFilter> metaArgs)
where T : vit_post
{
...
}
При условии, что vit_post
это супер тип.