Entity Framework: смешанные предикаты смешанных объектов - PullRequest
1 голос
/ 01 сентября 2011

Извините за мой ужасный английский.

Я пытаюсь расширить мою модель 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», не найден ».

Я что-то упускаю, я знаю, но не могу найти, что.

UPDATE

Я нашел альтернативное решение (и, возможно, правильное тоже), реализующее все мое выражение в соответствующих частичных классах сущностей. Например, у 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 Ответ

0 голосов
/ 18 сентября 2011

Вы еще не видели / не отвечали на мой вопрос, но если vit_postmeta и vit_post каким-либо образом связаны с наследованием, вы можете сделать что-то вроде:

public static Expression<Func<T, bool>> HasMetas<T>(IEnumerable<MetaFilter> metaArgs)
    where T : vit_post
{
    ...
}

Предполагая, что vit_post это супер тип.

...