Принуждение linq для выполнения внутренних соединений
Я пытаюсь заставить Linq закрепить внутреннее соединение между двумя таблицами. Я приведу пример.
CREATE TABLE [dbo].[People] (
[PersonId] [int] NOT NULL,
[Name] [nvarchar](MAX) NOT NULL,
[UpdatedDate] [smalldatetime] NOT NULL
... Other fields ...
)
CREATE TABLE [dbo].[CompanyPositions] (
[CompanyPositionId] [int] NOT NULL,
[CompanyId] [int] NOT NULL,
[PersonId] [int] NOT NULL,
... Other fields ...
)
Теперь я работаю с необычной базой данных, так как есть причина, по которой я не могу контролировать людей, которых нет в таблице People, но есть запись в CompanyPositions. Я хочу отфильтровать CompanyPosition с отсутствующими людьми, соединяя таблицы.
return (from pos in CompanyPositions
join p in People on pos.PersonId equals p.PersonId
select pos).ToList();
Linq считает это объединение избыточным и удаляет его из создаваемого SQL.
SELECT
[Extent1].[CompanyPositionId] AS [CompanyPositionId],
[Extent1].[CompanyId] AS [CompanyId],
....
FROM [dbo].[CompanyPositions] AS [Extent1]
Однако это не избыточно в моем случае. Я могу это исправить
// The min date check will always be true, here to force linq to perform the inner join
var minDate = DateTimeExtensions.SqlMinSmallDate;
return (from pos in CompanyPositions
join p in People on pos.PersonId equals p.PersonId
where p.UpdatedDate >= minDate
select pos).ToList();
Однако теперь это создает ненужное предложение where в моем SQL. Как чистейший я хотел бы удалить это. Любая идея или текущий дизайн базы данных связывают мои руки?
Ответы
Ответ 1
Поскольку PersonId объявлен NOT NULL
(и я предполагаю, что он объявлен как FK для людей), тогда я не уверен, как вы могли бы иметь CompanyPosition с человеком, который не назначен; и Linq не может видеть, как вы можете eiter, поэтому, поскольку вы заметили, что Linq считает избыточность соединения.
Ответ 2
Если вы используете LinqToSql, вы можете использовать LoadWith примерно так:
var context = new MyDataContext();
var options = new DataLoadOptions();
options.LoadWith<People>(x => x.CompanyPositions);
context.LoadOptions = options;
Ответ 3
Я не знаю, как заставить linq использовать соединение. Но следующий статус должен дать вам необходимый результат.
return (from pos in CompanyPositions
where (p in People select p.PersonId).Contains(pos.PersonId)
select pos).ToList();
Ответ 4
Преобразование ClientSide:
(
from pos in CompanyPositions
join p in People on pos.PersonId equals p.PersonId
select new {pos, p}
).ToList().Select(x => x.pos);
Более прямая фильтрация:
from pos in CompanyPositions
where pos.People.Any()
select pos