엔티티에 대한 링크 - SQL "IN" 절
T-SQL에서는 다음과 같은 쿼리를 사용할 수 있습니다.
SELECT * FROM Users WHERE User_Rights IN ("Admin", "User", "Limited")
LINQ to Entities 쿼리에서 이를 어떻게 복제하시겠습니까?그게 가능할까요?
당신은 그것에 대해 생각하는 방식으로 그것의 머리 위로 돌릴 필요가 있습니다.미리 정의된 적용 가능한 사용자 권한 집합에서 현재 항목의 사용자 권한을 찾기 위해 "in"을 수행하는 대신, 미리 정의된 사용자 권한 집합에 현재 항목의 적용 가능한 값이 포함되어 있는지 묻는 것입니다.이 방법은 .NET의 일반 목록에서 항목을 찾을 때와 정확히 같습니다.
LINQ를 사용하여 이 작업을 수행하는 방법에는 쿼리 구문을 사용하는 방법과 메서드 구문을 사용하는 방법 두 가지가 있습니다.기본적으로 동일하며 사용자의 선호도에 따라 서로 바꾸어 사용할 수 있습니다.
쿼리 구문:
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(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
문법적으로 이것은 더 복잡해 보입니다. 그리고 람다 표현식이나 대리인의 개념을 이해해야 무슨 일이 일어나고 있는지 알아낼 수 있습니다. 하지만 보시다시피, 이것은 코드를 상당히 응축시킵니다.
이 모든 것은 여러분의 코딩 스타일과 선호도에 따라 달라집니다. 제 세 가지 예는 모두 약간 다르게 같은 것을 합니다.
다른 방법으로는 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;
}
이것으로 당신의 목적은 충분할 것입니다.두 컬렉션을 비교하고 한 컬렉션의 값이 다른 컬렉션의 값과 일치하는지 확인합니다.
fea_Features.Where(s => selectedFeatures.Contains(s.feaId))
저는 이 상황에서 이너 조인을 하겠습니다.만약 내가 contains를 사용했다면, 일치하는 것이 하나라도 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();
Contains의 단점
두 개의 목록 개체가 있다고 가정합니다.
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();
또한 Entity Data Model에 대한 쿼리와 같은 SQL-IN 작업도 시도했습니다.저의 접근 방식은 큰 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 앞에 항상 "GUID"라는 단어가 있습니다.이걸 추가하지 않으면,ObjectQuery<T>.Where다음 예외를 발생시킵니다.
인수에 'Edm'이 입력됩니다.'Guid' 및 'Edm'.문자열'이(가) 이 작업에 호환되지 않습니다. 거의 같은 식, 행 6, 열 14입니다.
MSDN 포럼에서 이것을 발견했습니다. 염두에 두면 도움이 될 수 있습니다.
마티아스
모든 것이 나아지면 .NET 및 Entity Framework의 다음 버전을 기대합니다.:)
BenAlabaster 답변에 대한 대체 방법
먼저 쿼리를 다음과 같이 다시 작성할 수 있습니다.
var matches = from Users in people
where Users.User_Rights == "Admin" ||
Users.User_Rights == "Users" ||
Users.User_Rights == "Limited"
select Users;
확실히 이것은 더 '말투성'이고 쓰기에 고통스럽지만 모두 똑같이 작동합니다.
그래서 만약 우리가 이러한 종류의 LINQ 표현을 쉽게 만들 수 있는 유틸리티 방법이 있다면 우리는 사업을 할 것입니다.
유틸리티 메소드를 사용하여 다음과 같은 내용을 작성할 수 있습니다.
var matches = ctx.People.Where(
BuildOrExpression<People, string>(
p => p.User_Rights, names
)
);
이렇게 하면 다음과 같은 효과를 갖는 식을 만들 수 있습니다.
var matches = from p in ctx.People
where names.Contains(p.User_Rights)
select p;
그러나 더 중요한 것은 .NET 3.5 SP1에 대해 실제로 작동한다는 것입니다.
이를 가능하게 하는 배관 기능은 다음과 같습니다.
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);
}
저는 이 방법을 설명하려고 하지 않을 것입니다. 단, 기본적으로 이 방법은 값 Selector(즉, p = > p)를 사용하여 모든 값에 대한 술어 표현식을 구축합니다.User_Rights) 및 이들 술어를 함께 사용하여 전체 술어에 대한 식을 만듭니다.
출처: http://blogs.msdn.com/b/alexj/archive/2009/03/26/tip-8-writing-where-in-style-queries-using-linq-to-entities.aspx
실제 예:
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;
이 연산자는 정확히 IN 연산자는 아니지만 예상 결과를 얻는 데 도움이 될 수 있고 더 일반적인 접근 방식일 수 있습니다(두 컬렉션을 비교할 수 있기 때문에): INTRESS
여기 실제 사례가 있습니다.
var selected =
users.Where(u =>
new[] { "Admin", "User", "Limited" }.Intersect(new[] {u.User_Rights}).Any()
);
OR
var selected =
users.Where(u =>
new[] {u.User_Rights}.Intersect(new[] { "Admin", "User", "Limited" }).Any()
);
이 솔루션을 완전히 검증하려면 성능을 (현재 승인된 답변과 비교하여) 벤치마킹해야 할 것 같습니다.
편집:
Gert Arnold가 예를 들어 요청했듯이 (EF 6): 이 코드 조각은 이름 및/또는 성이 "John" 또는 "Doe"와 일치하는 사용자를 제공합니다.
// GET: webUsers
public async Task<ActionResult> Index()
{
var searchedNames = new[] { "John", "Doe" };
return
View(
await db
.webUsers
.Where(u => new[] { u.firstName, u.lastName }.Intersect(searchedNames).Any())
.ToListAsync()
);
//return View(await db.webUsers.ToListAsync());
}
쿼리 구문:
string[] month = { "jan", "feb", "mar" };
var qry = from c in populationdata
where c.birthmonth in month
select c;
월이 "month" 문자열 배열 "in"인 "population data"에서 레코드를 선택합니다.
진짜로?당신들은 사용해 본 적이 없습니다.
where (t.MyTableId == 1 || t.MyTableId == 2 || t.MyTableId == 3)
언급URL : https://stackoverflow.com/questions/857973/linq-to-entities-sql-in-clause
'programing' 카테고리의 다른 글
| Linkq를 사용하여 목록에서 일치하는 모든 값의 인덱스 가져오기 (0) | 2023.05.17 |
|---|---|
| CSS에서 img 태그의 src 속성에 해당하는 것을 설정할 수 있습니까? (0) | 2023.05.17 |
| mongoDB 접두사 와일드카드: 전체 텍스트 검색($text) 검색 문자열이 있는 부분 찾기 (0) | 2023.05.17 |
| PostgreSQL 새 줄 문자 (0) | 2023.05.17 |
| Bash 스크립트를 실행하지 않고 구문을 확인하려면 어떻게 해야 합니까? (0) | 2023.05.17 |