私たちは、ログ ビューアーに取り組んでいます。使用には、ユーザー、重大度などでフィルター処理するオプションがあります。Sql の時代には、クエリ文字列に追加していましたが、Linq でそれを行いたいと考えています。条件付きで where 句を追加するにはどうすればよいですか?
13 に答える
特定の基準を満たした場合にのみフィルタリングする場合は、次のようにします
var logs = from log in context.Logs
select log;
if (filterBySeverity)
logs = logs.Where(p => p.Severity == severity);
if (filterByUser)
logs = logs.Where(p => p.User == user);
このようにすることで、式ツリーをまさにあなたが望むものにすることができます。そうすれば、作成された SQL はまさに必要なものであり、それ以下ではありません。
リスト/配列に基づいてフィルタリングする必要がある場合は、次を使用します。
public List<Data> GetData(List<string> Numbers, List<string> Letters)
{
if (Numbers == null)
Numbers = new List<string>();
if (Letters == null)
Letters = new List<string>();
var q = from d in database.table
where (Numbers.Count == 0 || Numbers.Contains(d.Number))
where (Letters.Count == 0 || Letters.Contains(d.Letter))
select new Data
{
Number = d.Number,
Letter = d.Letter,
};
return q.ToList();
}
私はDarenと同様の答えを使用しましたが、IQueryableインターフェイスを使用しました。
IQueryable<Log> matches = m_Locator.Logs;
// Users filter
if (usersFilter)
matches = matches.Where(l => l.UserName == comboBoxUsers.Text);
// Severity filter
if (severityFilter)
matches = matches.Where(l => l.Severity == comboBoxSeverity.Text);
Logs = (from log in matches
orderby log.EventTime descending
select log).ToList();
これにより、データベースにアクセスする前にクエリが構築されます。コマンドは、最後の.ToList()まで実行されません。
条件付き言語クエリに関しては、フィルターとパイプのパターンが非常に好きです。
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/
基本的に、IQueryableとパラメーターを受け取るフィルターケースごとに拡張メソッドを作成します。
public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id)
{
return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query;
}
これを行う:
bool lastNameSearch = true/false; // depending if they want to search by last name,
これをwhere
ステートメントに含める:
where (lastNameSearch && name.LastNameSearch == "smith")
は、最終的なクエリが作成されるときに、lastNameSearch
クエリfalse
が姓検索の SQL を完全に省略することを意味します。
もう1つのオプションは、ここで説明するPredicateBuilderのようなものを使用することです。これにより、次のようなコードを記述できます。
var newKids = Product.ContainsInDescription ("BlackBerry", "iPhone");
var classics = Product.ContainsInDescription ("Nokia", "Ericsson")
.And (Product.IsSelling());
var query = from p in Data.Products.Where (newKids.Or (classics))
select p;
これはLinq2SQLでのみ機能することに注意してください。EntityFrameworkは、このメソッドが機能するために必要なExpression.Invokeを実装していません。この問題についてここで質問があります。
最近、同様の要件があり、最終的にこれを MSDN で見つけました。 Visual Studio 2008 の CSharp サンプル
ダウンロードの DynamicQuery サンプルに含まれているクラスを使用すると、実行時に次の形式で動的クエリを作成できます。
var query =
db.Customers.
Where("City = @0 and Orders.Count >= @1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");
これを使用すると、実行時にクエリ文字列を動的に構築し、それを Where() メソッドに渡すことができます。
string dynamicQueryString = "City = \"London\" and Order.Count >= 10";
var q = from c in db.Customers.Where(queryString, null)
orderby c.CompanyName
select c;
それは最も美しいものではありませんが、ラムダ式を使用してオプションで条件を渡すことができます。TSQL では、パラメーターをオプションにするために次の多くのことを行います。
WHERE フィールド = @FieldVar OR @FieldVar IS NULL
次のラムダを使用して同じスタイルを複製できます (認証を確認する例)。
MyDataContext db = new MyDataContext();
void RunQuery(string param1, string param2, int? param3){
Func checkUser = ユーザー =>
((param1.Length > 0)? user.Param1 == param1 : 1 == 1) &&
((param2.Length > 0)? user.Param2 == param2 : 1 == 1) &&
((param3 != null)? user.Param3 == param3 : 1 == 1);
ユーザーが見つかりましたUser = db.Users.SingleOrDefault(checkUser);
}
C# の && 演算子を使用するだけです。
var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")
編集:ああ、もっと注意深く読む必要があります。条件付きで句を追加する方法を知りたいと思っていました。その場合、私にはわかりません。:) 私がおそらく行うことは、いくつかのクエリを準備し、最終的に必要なものに応じて適切なクエリを実行することです。
外部メソッドを使用できます:
var results =
from rec in GetSomeRecs()
where ConditionalCheck(rec)
select rec;
...
bool ConditionalCheck( typeofRec input ) {
...
}
これは機能しますが、式ツリーに分解することはできません。つまり、Linq to SQL はすべてのレコードに対してチェック コードを実行します。
または:
var results =
from rec in GetSomeRecs()
where
(!filterBySeverity || rec.Severity == severity) &&
(!filterByUser|| rec.User == user)
select rec;
これは式ツリーで機能する可能性があり、Linq to SQL が最適化されることを意味します。
さて、私が考えたのは、フィルター条件を述語の一般的なリストに入れることができるということでした。
var list = new List<string> { "me", "you", "meyou", "mow" };
var predicates = new List<Predicate<string>>();
predicates.Add(i => i.Contains("me"));
predicates.Add(i => i.EndsWith("w"));
var results = new List<string>();
foreach (var p in predicates)
results.AddRange(from i in list where p.Invoke(i) select i);
その結果、「me」、「meyou」、および「mow」を含むリストが作成されます。
すべての述語を OR するまったく別の関数で述語を使用して foreach を実行することで、これを最適化できます。