Как я могу заставить LINQ to SQL выполнить INNER JOIN для внешнего ключа, который может содержать NULL? - PullRequest
2 голосов
/ 21 октября 2010

У меня очень простая настройка. Таблица «Узел» имеет обнуляемый внешний ключ «ObjectId». Это представлено в моей модели базы данных с ассоциацией «один ко многим». Теперь я хочу выполнить запрос, который дает мне все Node-объекты с определенным идентификатором объекта. В прямом SQL это очень просто:

SELECT Node.*, Object.*
FROM Node INNER JOIN Object
    ON Node.ObjectId = Object.ObjectId
WHERE Node.ObjectId = @objectId

Но теперь я хочу сделать то же самое в LINQ to SQL:

private static Func<MyDataContext, string, IQueryable<DataNode>> _queryGet =
        CompiledQuery.Compile(
            (MyDataContext context, string objectId) =>
                (from node in context.DataNodes
                 where node.ObjectId == objectId
                 select node));

var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<DataNode>(node => node.DataObject);
context.LoadOptions = loadOptions;

DataNode node = _queryGet.Invoke(context, objectId).FirstOrDefault();
...

Огорчает то, что LINQ всегда генерирует левое внешнее соединение для этого запроса, и ничто из того, что я пробовал, не имеет значения.

На первый взгляд, это имеет смысл. Внешний ключ ObjectId обнуляется, поэтому некоторые узлы не будут иметь связанный объект. Но в моем запросе я предоставляю идентификатор объекта. Меня не интересуют узлы без связанного объекта.

В этом случае ВНУТРЕННЕЕ СОЕДИНЕНИЕ - правильная вещь, но как мне убедить LINQ?

Ответы [ 4 ]

2 голосов
/ 22 октября 2010

Я думаю, вам просто нужно позволить этому левому внешнему соединению.Я представляю, когда дерево выражений преобразуется в SQL, объединение и предикат равенства считаются отдельными частями результирующего запроса.Другими словами, LEFT OUTER JOIN просто существует из-за того, что вы присоединяетесь к внешнему ключу, допускающему значение NULL, а часть равенства записывается впоследствии (так сказать).

Действительно ли это важно, чтоэто не переводить как хочешь?Тот факт, что вы не всегда получаете максимально эффективный запрос, является своего рода приемлемым компромиссом, когда вы используете LINQ to SQL.В большинстве случаев запросы довольно эффективны, если вы не делаете ничего сумасшедшего, и если вы действительно думаете, что это повлияет на производительность или что-то подобное, вы всегда можете написать хранимую процедуру, которую может использовать LINQ to SQL.

1 голос
/ 10 ноября 2010

Я в конце концов нашел хорошее решение для этого.Ответ заключается в том, чтобы просто получить LINQ to SQL.Вот так:

using (MyDataContext context = CreateDataContext())
{
    // Set the load options for the query (these tell LINQ that the
    // DataNode object will have an associated DataObject object just
    // as before).
    context.LoadOptions = StaticLoadOptions;

    // Run a plain old SQL query on our context.  LINQ will use the
    // results to populate the node object (including its DataObject
    // property, thanks to the load options).
    DataNode node = context.ExecuteQuery<DataNode>(
        "SELECT * FROM Node INNER JOIN Object " +
        "ON Node.ObjectId = Object.ObjectId " +
        "WHERE ObjectId = @p0",
        objectId).FirstOrDefault();

    //...
}
0 голосов
/ 04 февраля 2011

Кажется очень сложным для того, что я думаю, вы хотите.

Я бы форсировал соединения следующим образом:

from n in context.Nodes join o in context.Objects on n.ObjectId 
    equals o.Object_id select n
0 голосов
/ 22 октября 2010
loadOptions.LoadWith<DataNode>(node => node.DataObject); 

Вы неправильно поняли цель этого утверждения. Это никак не фильтрует результат. Он не переводится в sql, который может каким-либо образом фильтровать результат. INNER JOIN отфильтрует набор результатов, а LEFT JOIN - нет, поэтому LEFT JOIN - правильный выбор.

Если вы хотите отфильтровать узлы, вы должны использовать запрос, который включает критерии вашего фильтра:

from node in context.DataNodes  
where node.ObjectId == objectId  
where node.DataObject != null
select node

Рассмотрим разницу между нашими запросами, когда objectId равен нулю (переводчик запросов не проверяет значение objectId).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...