Yanıtlar:
Düşünme şekliniz açısından kafasını çevirmeniz gerekiyor. Geçerli öğenin kullanıcı haklarını önceden tanımlanmış geçerli kullanıcı hakları kümesinde bulmak için "giriş" yapmak yerine, geçerli öğenin uygulanabilir değerini içeriyorsa önceden tanımlanmış bir kullanıcı hakları kümesi sorarsınız. Bu, .NET'te normal bir listede bir öğeyi bulmanızla tamamen aynıdır.
Bunu LINQ kullanarak yapmanın iki yolu vardır, biri sorgu sözdizimini, diğeri ise yöntem sözdizimini kullanır. Temel olarak, bunlar aynıdır ve tercihinize bağlı olarak birbirinin yerine kullanılabilir:
Sorgu Sözdizimi:
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;
}
Yöntem Sözdizimi:
var selected = users.Where(u => new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights));
foreach(user u in selected)
{
//Do stuff on each selected user;
}
Bu durumda kişisel tercihim yöntem sözdizimi olabilir çünkü değişken atamak yerine, böyle bir anonim çağrı üzerinde foreach yapabiliriz:
foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
Sözdizimsel olarak bu daha karmaşık görünüyor ve neler olup bittiğini gerçekten anlamak için lambda ifadeleri veya delegeler kavramını anlamalısınız, ancak gördüğünüz gibi bu, kodu adil bir miktarda yoğunlaştırıyor.
Her şey kodlama stilinize ve tercihinize bağlıdır - örneklerimin üçü de aynı şeyi biraz farklı yapar.
Alternatif bir yol bile LINQ kullanmaz, aynı yöntem sözdizimini "where" yerine "FindAll" kullanarak değiştirebilir ve .NET 2.0'da da çalışacak aynı sonucu elde edebilirsiniz:
foreach(User u in users.FindAll(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
Bu sizin amacınıza yeter. İki koleksiyonu karşılaştırır ve bir koleksiyonun diğer koleksiyondakilerle eşleşen değerlere sahip olup olmadığını kontrol eder
fea_Features.Where(s => selectedFeatures.Contains(s.feaId))
VS2008 / .net 3.5 kullanıyorsanız, Alex James'in # 8 numaralı ipucuna bakın: http://blogs.msdn.com/alexj/archive/2009/03/26/tip-8-writing-where-in-style -queries kullanan-linq-to-entities.aspx
Aksi takdirde array.Contains (someEntity.Member) yöntemini kullanın.
Bu bağlamda İçsel Katılım'a gideceğim. Eğer içerecek olsaydım, tek bir maç olmasına rağmen 6 kez tekrar ederdi.
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();
İki liste nesnem olduğunu varsayalım.
List 1 List 2
1 12
2 7
3 8
4 98
5 9
6 10
7 6
İçerir kullanarak, Liste 2'deki her Liste 1 öğesini arayacak, bu da yinelemenin 49 kez olacağı anlamına gelir !!!
Ayrıca bir varlık veri modeli karşı sorgulama - bir SQL-IN benzeri bir şey ile çalışmaya çalıştı . Benim yaklaşım büyük bir OR-ifadesi oluşturmak için bir dize oluşturucu. Bu çok çirkin, ama korkarım şu an gitmek için tek yol bu.
Şimdi, bu şöyle görünüyor:
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());
}
}
Bu bağlamda GUID'lerle çalışma : Yukarıda görebileceğiniz gibi, sorgu dizesi parçalarında GUID'den önce her zaman "GUID" sözcüğü vardır. Bunu eklemezseniz ObjectQuery<T>.Where
, aşağıdaki istisnayı atar:
'Edm.Guid' ve 'Edm.String' bağımsız değişken türleri bu işlem için uyumsuzdur., Neredeyse ifade, satır 6, sütun 14'e eşittir.
Bunu MSDN Forumlarında buldum, aklınızda bulundurmanız yararlı olabilir.
Matthias
... her şey daha iyi olduğunda .NET ve Entity Framework'ün bir sonraki sürümünü dört gözle bekliyorum. :)
BenAlabaster cevabına alternatif bir yöntem
Her şeyden önce, sorguyu şu şekilde yeniden yazabilirsiniz:
var matches = from Users in people
where Users.User_Rights == "Admin" ||
Users.User_Rights == "Users" ||
Users.User_Rights == "Limited"
select Users;
Kesinlikle bu daha 'garip' ve yazmak için bir acı ama hepsi aynı şekilde çalışıyor.
Dolayısıyla, bu tür LINQ ifadeleri oluşturmayı kolaylaştıran bir yarar yöntemimiz olsaydı, işimizde olurduk.
yerinde bir yardımcı program ile böyle bir şey yazabilirsiniz:
var matches = ctx.People.Where(
BuildOrExpression<People, string>(
p => p.User_Rights, names
)
);
Bu, aşağıdakiyle aynı etkiye sahip bir ifade oluşturur:
var matches = from p in ctx.People
where names.Contains(p.User_Rights)
select p;
Ama daha da önemlisi aslında .NET 3.5 SP1'e karşı çalışıyor.
İşte bunu mümkün kılan sıhhi tesisat fonksiyonu:
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);
}
Ben esas olarak valueSelector (yani p => p.User_Rights) ve birlikte tam için bir ifade oluşturmak için tahmin ORs kullanarak tüm değerler için yüklem ifadesi oluşturur söylemek dışında bu yöntemi açıklamaya çalışacağız yüklem
Gerçek örnek:
var trackList = Model.TrackingHistory.GroupBy(x => x.ShipmentStatusId).Select(x => x.Last()).Reverse();
List<int> done_step1 = new List<int>() {2,3,4,5,6,7,8,9,10,11,14,18,21,22,23,24,25,26 };
bool isExists = trackList.Where(x => done_step1.Contains(x.ShipmentStatusId.Value)).FirstOrDefault() != null;
Ciddi anlamda? Siz hiç kullanmadınız
where (t.MyTableId == 1 || t.MyTableId == 2 || t.MyTableId == 3)
Checks = NumValues * NumRows
. Bu bir M * N tipi hesaplama olduğundan, her ikisi de küçükse, gerekli her bir kontrolü gerçekleştirme süresi de küçük olacaktır. Kısıtlamayı ekledim, böylece cjm30305, çözümünün neden zayıf olduğunu gösteren bir test ortamının nasıl kurulacağını bilecekti.
where new[] { 1, 2, 3 }.Contains(x)
daha az karşılaştırmawhere (x == 1 || x == 2 || x == 3)
?