動的なWHERE句をLINQステートメントにアセンブルする最良の方法は何ですか?
フォームには数十個のチェックボックスがあり、それらをLINQクエリにDictionary <string、List <string >>(Dictionary <fieldName、List <values >>)として返しています。
public IOrderedQueryable<ProductDetail> GetProductList(string productGroupName, string productTypeName, Dictionary<string,List<string>> filterDictionary)
{
var q = from c in db.ProductDetail
where c.ProductGroupName == productGroupName && c.ProductTypeName == productTypeName
// insert dynamic filter here
orderby c.ProductTypeName
select c;
return q;
}
(ソース: scottgu.com )
このようなものが必要ですか? Linq Dynamic Query Library を使用します(ダウンロードにはサンプルが含まれています)。
他の例については、 ScottGuのブログ をご覧ください。
LinqKitのPredicateBuilderを使用して、OrまたはAndを使用して複数のタイプセーフなラムダ式をチェーンすることもできます。
ユーザー入力に基づいてフィルターを追加し、where句をチェーンする必要がある同様のシナリオがあります。
サンプルコードを次に示します。
var votes = db.Votes.Where(r => r.SurveyID == surveyId);
if (fromDate != null)
{
votes = votes.Where(r => r.VoteDate.Value >= fromDate);
}
if (toDate != null)
{
votes = votes.Where(r => r.VoteDate.Value <= toDate);
}
votes = votes.Take(LimitRows).OrderByDescending(r => r.VoteDate);
単純なアプローチは、列が文字列のような単純型である場合です
public static IEnumerable<MyObject> WhereQuery(IEnumerable<MyObject> source, string columnName, string propertyValue)
{
return source.Where(m => { return m.GetType().GetProperty(columnName).GetValue(m, null).ToString().StartsWith(propertyValue); });
}
私も理解できるソリューションを思いつきました...「含む」メソッドを使用することで、好きなだけWHEREを連鎖できます。 WHEREが空の文字列である場合、それは無視されます(または全選択として評価されます)。 LINQで2つのテーブルを結合し、複数のwhere句を適用し、ビューに返されるモデルクラスにデータを入力する例を次に示します。 (これはすべて選択です)。
public ActionResult Index()
{
string AssetGroupCode = "";
string StatusCode = "";
string SearchString = "";
var mdl = from a in _db.Assets
join t in _db.Tags on a.ASSETID equals t.ASSETID
where a.ASSETGROUPCODE.Contains(AssetGroupCode)
&& a.STATUSCODE.Contains(StatusCode)
&& (
a.PO.Contains(SearchString)
|| a.MODEL.Contains(SearchString)
|| a.USERNAME.Contains(SearchString)
|| a.LOCATION.Contains(SearchString)
|| t.TAGNUMBER.Contains(SearchString)
|| t.SERIALNUMBER.Contains(SearchString)
)
select new AssetListView
{
AssetId = a.ASSETID,
TagId = t.TAGID,
PO = a.PO,
Model = a.MODEL,
UserName = a.USERNAME,
Location = a.LOCATION,
Tag = t.TAGNUMBER,
SerialNum = t.SERIALNUMBER
};
return View(mdl);
}
同じ質問( linqのユーザー定義フィルター )があり、@ tvanfossonがDynamic Linq( http://code.msdn.Microsoft.com/csharpsamples )について教えてくれました。
条件が含まれているかどうかを動的に決定するために三項演算子を使用する方がはるかに簡単に見える
リストproductList = new List();
productList =
db.ProductDetail.Where(p => p.ProductDetailID > 0 //Example prop
&& (String.IsNullOrEmpty(iproductGroupName) ? (true):(p.iproductGroupName.Equals(iproductGroupName)) ) //use ternary operator to make the condition dynamic
&& (ID == 0 ? (true) : (p.ID == IDParam))
).ToList();
Any()拡張メソッドを使用できます。次は私のために働くようです。
XStreamingElement root = new XStreamingElement("Results",
from el in StreamProductItem(file)
where fieldsToSearch.Any(s => el.Element(s) != null && el.Element(s).Value.Contains(searchTerm))
select fieldsToReturn.Select(r => (r == "product") ? el : el.Element(r))
);
Console.WriteLine(root.ToString());
ここで、「fieldsToSearch」と「fieldsToReturn」は両方ともListオブジェクトです。
CodePlexのこのプロジェクトには、あなたが望むものがあります。
System.Linq.Dynamic- http://dynamiclinq.codeplex.com/
プロジェクトの説明
System.Linq.Dynamicを拡張して、Entity FrameworkまたはIQueryableをサポートするプロバイダーに対して文字列で定義されたLambda式の実行をサポートします。
これは Scott Guthrie's Blog にあるソースコードの拡張であるため、次のようなことができます。
そして、このようなもの:
これは、誰かが興味を持っている場合に私が思いついた解決策です。
https://kellyschronicles.wordpress.com/2017/12/16/dynamic-predicate-for-a-linq-query/
まず、使用する必要がある単一の要素タイプ(Of TRow As DataRow)を特定し、次に使用している「ソース」を特定し、そのソースに識別子を結び付けます((source As TypedTableBase(Of TRow))。次に、述語、または渡されるWHERE句(述語As Func(Of TRow、Boolean))がtrueまたはfalseとして返され、返された情報の順序付け方法(OrderByField As String)を特定します。関数は、述語(EnumerableRowCollection(Of TRow))の条件を満たしたデータ行のコレクションであるEnumerableRowCollection(Of TRow)を返します。これは基本的な例です。もちろん、注文フィールドには、 null、またはその状況を適切に処理し、列名(これを気にせずに厳密に型指定されたデータソースを使用している場合、列の名前を変更する)が標準であることを確認してください。