Принуждение 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