ПРИСОЕДИНИТЕСЬ и ОСТАВЛЕННОЕ СОЕДИНЕНИЕ, эквивалентное в LINQ

Я стараюсь максимально избегать использования значений NULL в базе данных. Это означает, что символьные поля всегда не равны нулю. То же самое для числовых полей, особенно для обозначения денег или аналогичных (доли, единицы и т. Д.).

У меня есть 2 исключения:

  1. Даты, когда дата может быть неизвестна (например, DivorcedOn)
  2. Необязательные внешние связи ключей (MarriedToPersonId). Хотя иногда я использовал «пустые» строки в таблице внешнего ключа и делал обязательным отношение (например, JobDescriptionCode)

Я также иногда использовал явные битовые поля для «неизвестно» / «не set "(например, JobDescriptionCode и IsEmployeed).

У меня есть несколько основных причин, по которым:

  1. NULL всегда будут вызывать проблемы в числовых полях. Всегда. Всегда. Всегда. Неважно, насколько вы осторожны, выберите X + Y, так как произойдет Total, и он вернет NULL.
  2. Значения NULL могут легко вызвать проблемы в строковых полях, обычно в адресных полях (например, выберите AddrLine1 + AddrLine2 из Адреса).
  3. Защита от NULL на уровне бизнес-логики - это утомительная трата усилий ... просто не впускайте их в БД, и вы можете сохранить сотни строк кода.

Мои предпочтения по умолчанию:

  • Строки -> "", иначе пустая строка
  • Числа -> 0
  • Даты -> Сегодня или NULL (см. Исключение № 1)
  • Бит -> ложь
6
задан Brian David Berman 18 June 2009 в 14:40
поделиться

3 ответа

. Возможно, вам придется немного подправить это, поскольку я собирался сойти с дистанции, но есть о парочке важных вещей, о которых следует помнить. Если ваши отношения настроены правильно в вашем dbml, вы должны иметь возможность неявно выполнять внутренние соединения и просто получать доступ к данным через исходную таблицу. Кроме того, левые соединения в LINQ не так просты, как мы могли бы надеяться, и вам нужно пройти через синтаксис DefaultIfEmpty, чтобы это произошло. Я создал здесь анонимный тип, но вы можете захотеть поместить в класс DTO или что-то в этом роде. Я также не знал, что вы хотите сделать в случае нулей, но вы можете использовать ?? синтаксис для определения значения, которое будет присвоено переменной, если значение равно нулю. Дайте мне знать, если у вас возникнут дополнительные вопросы ...

var query = (from a in context.Appointment
join b in context.AppointmentFormula on a.AppointmentId equals b.AppointmentId into temp
from c in temp.DefaultIfEmpty()
join d in context.AppointmentForm on a.AppointmentID equals e.AppointmentID into temp2
from e in temp2.DefaultIfEmpty()
where a.RowStatus == 1 && c.RowStatus == 1 && a.Type == 1
select new {a.AppointmentId, a.Status, a.Type, a.Title, c.Days ?? 0, a.Type.Description, e.FormID ?? 0}).OrderBy(a.Type);
5
ответ дан 8 December 2019 в 02:35
поделиться
SELECT A.X, B.Y
FROM A JOIN B ON A.X = B.Y

Этот вызов метода linq (для соединения) сгенерирует указанное выше соединение.

var query = A.Join
(
  B,
  a => a.x,
  b => b.y,
  (a, b) => new {a.x, b.y} //if you want more columns - add them here.
);

SELECT A.X, B.Y
FROM A LEFT JOIN B ON A.X = B.Y

Эти вызовы метода linq (для GroupJoin, SelectMany, DefaultIfEmpty) будет производить указанное выше левое соединение

var query = A.GroupJoin
(
  B,
  a => a.x,
  b => b.y,
  (a, g) => new {a, g}
).SelectMany
(
  z => z.g.DefaultIfEmpty(),
  (z, b) =>
    new  { x = z.a.x, y = b.y } //if you want more columns - add them here.
);

Ключевой концепцией здесь является то, что методы Linq производят результаты в иерархической форме, а не в плоских формах строки-столбца.

  • Linq ' s GroupBy выдает результаты, сформированные в виде иерархии с ключом группировки, соответствующим коллекции элементов (которая может быть не пустой). Предложение SQL GroupBy создает ключ группировки с агрегированными значениями - нет никакой подгруппы для работы.
  • Аналогичным образом, Linq GroupJoin создает иерархическую форму - родительская запись соответствует коллекции дочерних записей (которая может быть пустой). Sql LEFT JOIN создает родительскую запись, соответствующую каждой дочерней записи, или пустую дочернюю запись, если других совпадений нет. Чтобы получить форму Sql из формы Linq, нужно распаковать коллекцию дочерних записей с помощью SelectMany - и обработать пустые коллекции дочерних записей с помощью DefaultIfEmpty .

И вот моя попытка определить этот sql-код в вопросе:

var query =
  from a in Appointment
  where a.RowStatus == 1
  where a.Type == 1
  from b in a.AppointmentFormula.Where(af => af.RowStatus == 1).DefaultIfEmpty()
  from d in a.TypeRecord //a has a type column and is related to a table named type, disambiguate the names
  from e in a.AppointmentForm.DefaultIfEmpty()
  order by a.Type
  select new { a.AppointmentId, a.Status, a.Type, a.Title, b.Days, d.Description, e.Form }
29
ответ дан 8 December 2019 в 02:35
поделиться

Если вы хотите сохранить (NOLOCK) подсказки, я написал в блоге удобное решение с использованием методов расширения в C#. Обратите внимание, что это то же самое, что добавить подсказки nolock к каждой таблице в запросе.

1
ответ дан 8 December 2019 в 02:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: