T-SQL では、次のようなクエリを作成できます。
SELECT * FROM Users WHERE User_Rights IN ("Admin", "User", "Limited")
LINQ to Entities クエリでそれをどのように複製しますか? それは可能ですか?
T-SQL では、次のようなクエリを作成できます。
SELECT * FROM Users WHERE User_Rights IN ("Admin", "User", "Limited")
LINQ to Entities クエリでそれをどのように複製しますか? それは可能ですか?
あなたはそれについて考えているという点で、それを逆さまにする必要があります。"in" を実行して、適用可能なユーザー権利の事前定義されたセットで現在のアイテムのユーザー権利を見つけるのではなく、現在のアイテムの適用可能な値が含まれているかどうか、事前定義されたユーザー権利のセットを尋ねています。これは、.NET の通常のリストで項目を検索する方法とまったく同じです。
LINQ を使用してこれを行う方法は 2 つあります。1 つはクエリ構文を使用し、もう 1 つはメソッド構文を使用します。基本的に、それらは同じであり、好みに応じて交換可能に使用できます。
クエリ構文:
var selected = from u in users
where new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights)
select u
foreach(user u in selected)
{
//Do your stuff on each selected user;
}
メソッドの構文:
var selected = users.Where(u => new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights));
foreach(user u in selected)
{
//Do stuff on each selected user;
}
この例での私の個人的な好みはメソッド構文かもしれません。変数を割り当てる代わりに、次のような匿名呼び出しで foreach を実行できるからです。
foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
構文的には、これはより複雑に見えます。実際に何が起こっているのかを理解するには、ラムダ式またはデリゲートの概念を理解する必要がありますが、ご覧のとおり、コードはかなり凝縮されています。
それはすべて、コーディング スタイルと好みに依存します。私の 3 つの例はすべて、同じことを少しずつ異なる方法で行っています。
LINQ を使用しない別の方法もあります。「where」を「FindAll」に置き換えた同じメソッド構文を使用して、同じ結果を得ることができます。これは .NET 2.0 でも機能します。
foreach(User u in users.FindAll(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
これで目的は十分です。2 つのコレクションを比較し、一方のコレクションの値が他方のコレクションの値と一致するかどうかをチェックします。
fea_Features.Where(s => selectedFeatures.Contains(s.feaId))
このコンテキストでは、内部結合を使用します。含むを使用した場合、一致が 1 つしかないにもかかわらず、6 回反復されます。
var desiredNames = new[] { "Pankaj", "Garg" };
var people = new[]
{
new { FirstName="Pankaj", Surname="Garg" },
new { FirstName="Marc", Surname="Gravell" },
new { FirstName="Jeff", Surname="Atwood" }
};
var records = (from p in people join filtered in desiredNames on p.FirstName equals filtered select p.FirstName).ToList();
2 つのリスト オブジェクトがあるとします。
List 1 List 2
1 12
2 7
3 8
4 98
5 9
6 10
7 6
Contains を使用すると、List 2 内の List 1 の各項目が検索されます。つまり、繰り返しが 49 回発生します!!!
これは、LINQ 拡張メソッドを直接使用して in 句をチェックできる方法である可能性があります。
var result = _db.Companies.Where(c => _db.CurrentSessionVariableDetails.Select(s => s.CompanyId).Contains(c.Id)).ToList();
また、SQL-IN のようなもの、つまり Entity Data Modelに対してクエリを実行しようとしました。私のアプローチは、大きな OR 式を構成する文字列ビルダーです。それはひどく醜いことですが、残念ながら今はそれしか方法がありません。
さて、それは次のようになります。
Queue<Guid> productIds = new Queue<Guid>(Products.Select(p => p.Key));
if(productIds.Count > 0)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}.ProductId = Guid\'{1}\'", entities.Products.Name, productIds.Dequeue());
while(productIds.Count > 0)
{
sb.AppendFormat(" OR {0}.ProductId = Guid\'{1}\'",
entities.Products.Name, productIds.Dequeue());
}
}
このコンテキストでの GUID の操作 : 上記でわかるように、クエリ文字列フラグメントの GUID ifself の前には常に "GUID" という単語があります。これを追加しないとObjectQuery<T>.Where
、次の例外がスローされます。
引数の型 'Edm.Guid' と 'Edm.String' は、この操作に対して互換性がありません。ほぼ等しい式、6 行目、14 列目。
これは MSDN フォーラムで見つかりました。覚えておくと役立つ場合があります。
マティアス
... すべてが改善された .NET と Entity Framework の次のバージョンを楽しみにしています。:)
An alternative method to BenAlabaster answer
First of all, you can rewrite the query like this:
var matches = from Users in people
where Users.User_Rights == "Admin" ||
Users.User_Rights == "Users" ||
Users.User_Rights == "Limited"
select Users;
Certainly this is more 'wordy' and a pain to write but it works all the same.
So if we had some utility method that made it easy to create these kind of LINQ expressions we'd be in business.
with a utility method in place you can write something like this:
var matches = ctx.People.Where(
BuildOrExpression<People, string>(
p => p.User_Rights, names
)
);
This builds an expression that has the same effect as:
var matches = from p in ctx.People
where names.Contains(p.User_Rights)
select p;
But which more importantly actually works against .NET 3.5 SP1.
Here is the plumbing function that makes this possible:
public static Expression<Func<TElement, bool>> BuildOrExpression<TElement, TValue>(
Expression<Func<TElement, TValue>> valueSelector,
IEnumerable<TValue> values
)
{
if (null == valueSelector)
throw new ArgumentNullException("valueSelector");
if (null == values)
throw new ArgumentNullException("values");
ParameterExpression p = valueSelector.Parameters.Single();
if (!values.Any())
return e => false;
var equals = values.Select(value =>
(Expression)Expression.Equal(
valueSelector.Body,
Expression.Constant(
value,
typeof(TValue)
)
)
);
var body = equals.Aggregate<Expression>(
(accumulate, equal) => Expression.Or(accumulate, equal)
);
return Expression.Lambda<Func<TElement, bool>>(body, p);
}
I'm not going to try to explain this method, other than to say it essentially builds a predicate expression for all the values using the valueSelector (i.e. p => p.User_Rights) and ORs those predicates together to create an expression for the complete predicate
真剣に?使ったことのない皆さん
where (t.MyTableId == 1 || t.MyTableId == 2 || t.MyTableId == 3)