2014-10-10 88 views
2

我一直在研究如何動態地對linq進行查詢。我爲Web應用程序創建了一個UI,允許他們從數據庫中選擇屬性並設置動態創建報告的子句。我在堆棧或其他網站上看到的所有問題都使用Dynamic Linq和LinqKit來解決問題,例如Here。但是我找不到表達語法的解決方案。動態Linq到實體

// This attempts to grab out a title whose from the Database whose 
// Copyright Date equals 2006 
propName = "CopyrightDate"; 
Model.Titles.Where(t => t.GetType().GetProperty(propName).GetValue(t, null) == "2006"); 

我想要做這樣的事情,但在Linq to Entities。 Linq到實體不支持反射那樣,我不想把所有的數據都拉出來,然後運行Linq到Object這個DB太大。任何關於如何在Dynamic Linq中編寫這些內容的建議。如果您可以將類型轉換爲屬性類型,則可以使用獎勵分數,這可以使用標準運算符(==,>,<等)進行evaultuated。

+0

你已經將問題與顯示解決這個確切問題的方法聯繫起來,當然還有其他許多可以通過一些基礎研究發現的問題。 – Servy 2014-10-10 17:04:04

回答

0

這裏是如何使用Dynamic Linq重寫查詢:

var propName = "CopyrightDate"; 
var propValue = "2006"; 
Model.Titles.Where(string.Format("{0}[email protected]", propName), propValue); 

string.Format("{0}[email protected]", propName)產生的查詢字符串爲Where子句,在這種情況下將是"[email protected]"@0指定查詢的參數,該參數將變爲propValue

+0

這似乎生成正確的SQL,我需要從選擇,我可以通過 Model.Titles.Where(string.Format(「{0} = @ 0」,propName),propValue)可以拉出TitleName。選擇(「TitleName」)但從這裏我不能做FirstOrDefault()和> ToList()擴展不在那裏。任何想法如何做到這一點 – 2014-10-10 17:35:14

+1

@ johnny5一旦你做'FirstOrDefault'你不能'ToList',因爲它是一個單一的項目。在[source](http://dynamiclinq.codeplex.com/SourceControl/latest#DynamicLinq/System.Linq.Dynamic/Dynamic中選擇(字符串)'。cs)返回一個無類型的'IQueryable'(即不是'IQueryable '),所以你需要通過轉換到你正在創建的字段的特定類型,即'Select(「TitleName」)。Cast .FirstOrDefault()'等等。 – dasblinkenlight 2014-10-10 17:43:04

+0

我只是說這兩個擴展都無法訪問,我知道你不能鏈接它們:)。我將這個例子轉換爲一個更簡單的東西,它只是使用一個ID。我正在嘗試這種情況,但是我一直收到一個異常「System.Linq.Queryable.Cast (system.linq.iqueryable)is'method',它在給定的上下文中無效」 var id = Model。標題.Where(string.Format(「{0} = @ 0」,propName),propValue).Select(「ID」)。AsQueryable()。Cast .FirstOrDefault(); 我也試過這個代碼.AsQueryAble()//(對不起Idk如何格式化這些註釋) – 2014-10-10 17:55:30

1

什麼是LINQ-to-entities Where擴展方法想要的是Expression<Func<T, bool>>。您可以創建這樣的表達是這樣的:

// Create lambda expression: t => t.CopyrightDate == "2006" 
ParameterExpression parameter = Expression.Parameter(typeof(T), "t"); 
var lambda = Expression.Lambda<Func<T, bool>>(
    Expression.Equal(
     Expression.Property(parameter, "CopyrightDate"), 
     Expression.Constant("2006") 
    ), 
    parameter 
); 

其中T是包含CopyrightDate屬性類的類型。

var result = context.Titles 
    .Where(lambda) 
    .ToList(); 

稍微更通用的解決方案是:

Expression<Func<T, bool>> Comparison<T>(ExpressionType comparisonType, 
             string propertyName, object compareTo) 
{ 
    ParameterExpression parameter = Expression.Parameter(typeof(T), "t"); 
    MemberExpression property = Expression.Property(parameter, propertyName); 
    ConstantExpression constant = Expression.Constant(compareTo); 
    Expression body = Expression.MakeBinary(comparisonType, property, constant); 
    return Expression.Lambda<Func<T, bool>>(body, parameter); 
} 
+0

我把它切換到了一個greaterthan,但問題是操作不起作用於可爲空的類型 'DateTime testDate = new DateTime(2006); ParameterExpression parameter = Expression.Parameter(typeof(Title),「t」); VAR拉姆達= Expression.Lambda >( Expression.GreaterThan( Expression.Property(參數 「CopyrightDate」), Expression.Constant(testDate) ) 參數 ); ' – 2014-10-10 17:44:23

+1

你的表格列是什麼類型?如果它是日期時間列,你不能比較'column = 2006'!你將不得不比較(在SQL中)'YEAR(column)= 2006'。或者,如果它是一個數字列'column = 2006'或者它是一個文本列'column ='2006''。我建議你在嘗試創建一個複雜的表達式樹之前首先創建一個可用的非動態查詢。 – 2014-10-10 17:58:35