动态附加LINQ Join

时间:2013-08-02 15:48:44

标签: c# linq linqkit

我的数据层中有一个方法,我传入一组搜索参数,使用LINQKit中的PredicateBuilder类动态构建所需的'where'子句,然后执行LINQ查询返回对象列表。

在某些情况下,搜索条件可能包含库表中不存在的类别名称,然后我需要加入此表以执行必要的查询。之所以这样做是因为每本书可能有数百个类别,出于优化原因,我只想在实际需要时执行连接。

现在我的问题是,是否可以动态地将此连接附加到LINQ查询?

经过几次努力试图让它发挥作用后,我不幸地不得不求助于“剪切和粘贴”的模式,我非常不喜欢这种模式,但需要一些有用的东西才能让它“出门” ”。

以下代码是一个变量,其变量重命名为我目前所拥有的(即这不是一个真正的库应用程序!):

public IEnumerable<ILibrarySearchResultsDTO> SearchLibrary(ISearchLibrary searchValues)
{
    var whereStatement = PredicateBuilder.True<Library>();

    bool categorySearch = false;

    if (!string.IsNullOrEmpty(searchValues.AuthorFirstName))
        whereStatement = whereStatement.And(q => q.AuthorFirstName == searchValues.AuthorFirstName);

    if (!string.IsNullOrEmpty(searchValues.AuthorLastName))
        whereStatement = whereStatement.And(q => q.AuthorLastName == searchValues.AuthorLastName);

    if (!string.IsNullOrEmpty(searchValues.CategoryName))
        categorySearch = true;

    var libraryObjectSet = Context.CreateObjectSet<Library>();
    LibraryObjectSet.MergeOption = MergeOption.NoTracking;

    var categoriesObjectSet = Context.CreateObjectSet<Categories>();
    categoriesObjectSet.MergeOption = MergeOption.NoTracking;

    if (!categorySearch)
    {
        var query = from lib in libraryObjectSet
                    .Where(whereStatement)
                    .Take(ConfigHelper.MaxQueryRecords)
                    .AsExpandable()
                    select new LibrarySearchResultsDTO()
                    {
                        BookName = lib.BookName,
                        AuthorFirstName = lib.AuthorFirstName,
                        AuthorLastName = lib.AuthorLastName,
                        ISBN = lib.ISBN
                    };
    }
    else
    {
        var query = from lib in LibraryObjectSet
                    .Where(whereStatement)
                    .Take(ConfigHelper.MaxQueryRecords)
                    .AsExpandable()
                    join categories_LKP in categoriesObjectSet on new { CategoryID = lib.CategoryID, CategoryName = searchValues.CategoryName } 
                        equals new { CategoryID = categories_LKP.CategoryID, CategoryName = categories_LKP.CategoryName }
                    select new LibrarySearchResultsDTO()
                    {
                        BookName = lib.BookName,
                        AuthorFirstName = lib.AuthorFirstName,
                        AuthorLastName = lib.AuthorLastName,
                        ISBN = lib.ISBN
                    };      
    }

    return query.ToList();
}

我必须在Notepad ++中创建示例代码,因为这是一个人为的例子,我无法检查它是否编译。应该这样做(我希望!)。

2 个答案:

答案 0 :(得分:1)

如果有LibraryCategory的导航属性,您可以动态添加另一个谓词:

if (!string.IsNullOrEmpty(searchValues.CategoryName))
{
   whereStatement = whereStatement
                   .And(q => q.Categories
                        .Any(c => c.CategoryName == searchValues.CategoryName));
}

如果导航属性不存在,您仍然可以在谓词中使用连接,而不必复制整个查询。但这可能是添加导航属性的一个很好的理由。

答案 1 :(得分:0)

您可以像下面的通用函数一样使用Reflection API ...它编译具有未知类型的动态查询...

 IQueryable<T> getQuery<T>(T myTableEntity, string[] arrayOfQueryTerms, Expression<Func<T, bool>> predicate)
 { 
    var fieldOrProperty = getMemberInfo(predicate);
 }

 MemberInfo getmemberInfo<T>(Expression<Func<T,bool> expr)
 { 
     var memberExpr = expr as MemberExpression;
     if (memberExpr != null) return memberExpr.Member;
         throw new ArgumentException();
 }

var q = getQuery<FooTable>(foo, new[]{"Bar","Baz"}, x=>x.FieldName);