实体框架:混合实体的混合谓词

时间:2011-09-01 14:40:07

标签: linq c#-4.0 entity-framework-4 linqkit

对不起我糟糕的英语。

我正在尝试扩展我的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;
    }
//[...]
}

...使用表达式HasMetas扩展实体“vit_post”。

使用此代码段,我按预期获得实体的子集:

    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表相关的所有表达式。

My Search类为每个实体提供了一个私有方法。类似的东西:

            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 :(得分:0)

您还没有看到/回答我的问题,但如果vit_postmetavit_post以任何方式通过继承相关联,您可以执行以下操作:

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

假设vit_post是超类型。

相关问题