Если вы посмотрите на исходный код для итератора ArrayList
(частный вложенный класс Itr
), вы увидите недостаток в коде.
Код должен быть с ошибкой, быстрый, который делается внутри итератора внутри, вызывая checkForComodification()
, однако hasNext()
не делает этот вызов, вероятно, по соображениям производительности.
Вместо hasNext()
:
public boolean hasNext() {
return cursor != size;
}
Это означает, что когда вы находитесь в элементе second last в списке, а затем удалите элемент (любой элемент), размер уменьшается, а hasNext()
думает, что вы 're на последнем элементе (которого вы не были) и возвращает false
, пропуская итерацию последнего элемента без ошибок.
OOPS !!!!
В Лямбде:
var persons = Persons.Where(p=>(p.PersonLocations.Select(ps=>ps.Location)
.Where(l=>l.Description == "Amsterdam").Count() > 0)
&& (p.PersonRoles.Select(pr=>pr.Role)
.Where(r=>r.Description == "Student").Count() > 0));
результат запроса:
SELECT [t0].[personId] AS [PersonId], [t0].[description] AS [Description]
FROM [Persons] AS [t0]
WHERE (((
SELECT COUNT(*)
FROM [personlocations] AS [t1]
INNER JOIN [Locations] AS [t2] ON [t2].[locationid] = [t1].[locationid]
WHERE ([t2].[description] = @p0) AND ([t1].[personid] = [t0].[personId])
)) > @p1) AND (((
SELECT COUNT(*)
FROM [PersonRoles] AS [t3]
INNER JOIN [Roles] AS [t4] ON [t4].[roleid] = [t3].[roleid]
WHERE ([t4].[description] = @p2) AND ([t3].[personid] = [t0].[personId])
)) > @p3)
Используя Содержит ():
var persons = Persons
.Where(p=>(p.Personlocations.Select(ps=>ps.Location)
.Select(l=>l.Description).Contains("Amsterdam")) &&
(p.PersonRoles.Select(pr=>pr.Role)
.Select(r=>r.Description).Contains("Student")));
результат запроса:
SELECT [t0].[personId] AS [PersonId], [t0].[description] AS [Description]
FROM [Persons] AS [t0]
WHERE (EXISTS(
SELECT NULL AS [EMPTY]
FROM [personlocations] AS [t1]
INNER JOIN [Locations] AS [t2] ON [t2].[locationid] = [t1].[locationid]
WHERE ([t2].[description] = @p0) AND ([t1].[personid] = [t0].[personId])
)) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM [PersonRoles] AS [t3]
INNER JOIN [Roles] AS [t4] ON [t4].[roleid] = [t3].[roleid]
WHERE ([t4].[description] = @p1) AND ([t3].[personid] = [t0].[personId])
))
соединение использования ():
var persons = Persons
.Join(Personlocations, p=>p.PersonId, ps=>ps.Personid,
(p,ps) => new {p,ps})
.Where(a => a.ps.Location.Description =="Amsterdam")
.Join(PersonRoles,
pr=> pr.p.PersonId, r=>r.Personid,(pr,r) => new {pr.p,r})
.Where(a=>a.r.Role.Description=="Student")
.Select(p=> new {p.p});
Результат запроса:
SELECT [t0].[personId] AS [PersonId], [t0].[description] AS [Description]
FROM [Persons] AS [t0]
INNER JOIN [personlocations] AS [t1] ON [t0].[personId] = [t1].[personid]
INNER JOIN [Locations] AS [t2] ON [t2].[locationid] = [t1].[locationid]
INNER JOIN [PersonRoles] AS [t3] ON [t0].[personId] = [t3].[personid]
INNER JOIN [Roles] AS [t4] ON [t4].[roleid] = [t3].[roleid]
WHERE ([t4].[description] = @p0) AND ([t2].[description] = @p1)
можно хотеть тест, какой быстрее с большими данными.
Удача.
Giuliano Lemes
Хорошо, LINQ не имеет никакого условия насколько я могу сказать. Лямбда-выражения действительно работают с любым ().
Примечание:
Поскольку он находится в EF v1, мы не будем иметь PersonLocation и PersonRole , сгенерированные как объекты, например что делает LINQ2SQL (ответ выше описывает сценарий LINQ2SQL, который не относится к вопросу.)
Решение 1:
Persons.Include("Role").Include("Location") // Include to load Role and Location
.Where(p => p.Role.Any(r => r.description == "Student")
&& p.Location.Any(l => l.description == "Amsterdam")).ToList();
Это выглядит красиво и просто, но генерирует уродливый сценарий SQL и его производительность в порядке.
Решение 2:
Вот неполадки.
// Find out all persons in the role
// Return IQuerable<Person>
var students = Roles.Where(r => r.description == "Student")
.SelectMany(r => r.Person);
// Find out all persons in the location
// Return IQuerable<Person>
var personsInAmsterdam = Locations.Where(l=> l.description == "Amsterdam")
.SelectMany(l=>l.Person);
// Find out the intersection that gives us students in Admsterdam.
// Return List<Person>
var AdmsterdamStudents = students.Intersect(personsInAmsterdam).ToList();
Объедините три приведенных выше шага в один:
//Return List<Person>
var AdmsterdamStudents = Roles.Where(r => r.description == "Student")
.SelectMany(r => r.Person)
.Intersect
(
Locations
.Where(l=> l.description == "Amsterdam")
.SelectMany(l=>l.Person)
).ToList();
Это своего рода многословие. Но это генерирует чистый SQL-запрос и работает хорошо.
Подробнее об этом, о том, как и почему Entities обрабатывает многие ко многим:
Блог ASP.NET - сопоставления "многие ко многим" в Entity Framework