Я просмотрел множество статей по этому вопросу, и либо представленные решения не сработали для меня, либо, возможно, я просто недостаточно четко их понимаю. В любом случае, рискуя быть дублирующим, я представляю свою проблему для вашего обзора.
У меня есть база данных контактов, которую я хочу найти ...
Каждый контакт связан с одним человеком (игнорировать отношения учреждения на данный момент) Каждый контакт также связан с несколькими записями электронной почты и телефона в других таблицах (каждое сообщение электронной почты и телефон являются исключительными для записи контакта).
Я хотел бы иметь возможность вернуть контакт, удовлетворяющий запросу, к записям электронной почты и / или телефонным записям. Таким образом, контакт может иметь несколько адресов электронной почты. Если мой запрос «попадет» на ЛЮБОЕ из электронных писем, я хочу, чтобы ОДИН контакт вернулся со ВСЕМИ электронными письмами (и телефонами), связанными с контактом, включенным в результаты.
Поэтому я ищу в почтовом домене «hollywood» , Существует один контакт с доменом электронной почты, равным «Голливуд». Этот контакт также имеет два других адреса электронной почты, связанных с ним. Я хочу вернуть одну запись, содержащую все эти записи. (Я фанат Моргана Фримена, поэтому я составил следующие данные - это ЛОЖЬ!)
Конечно, я выполняю такой запрос в SQL Server Management Studio вернет вам 3 записи. Один для каждой записи электронной почты, связанной с контактом. Однако я проецирую результаты в один объект, в который будут помещены несколько электронных писем (и телефонов), чтобы мне не приходилось иметь дело с несколькими объектами для одного и того же контакта.
Запрос построен в Linq. Я добавил строку "группа", думая, что она устранит дубликаты ...
var query = from rContact in qryContacts
group rContact by rContact.contact_id into grpContact
join rPerson in ctx.people
on grpContact.FirstOrDefault().person_id equals rPerson.person_id
join rEmail in ctx.emails
on grpContact.FirstOrDefault().contact_id equals rEmail.contact_id into emailGroup
from subEmails in emailGroup.DefaultIfEmpty()
select new PersonalContact
{
ID = grpContact.FirstOrDefault().contact_id,
Label = grpContact.FirstOrDefault().label,
Notes = grpContact.FirstOrDefault().notes,
Prefix = rPerson.prefix,
FirstName = rPerson.first_name,
MiddleName = rPerson.middle_name,
LastName = rPerson.last_name,
Suffix = rPerson.suffix,
AKA = rPerson.aka,
DOB = rPerson.dob,
IsFemale = rPerson.is_female,
Emails = emailGroup.Select(e=> new Email
{
ID = e.email_id,
Label = e.label,
Notes = e.notes,
Preferred = e.is_preferred,
Category = e.email_category,
LocalPart = e.email_local_part,
Domain = e.email_domain,
TopLevelDomain = e.email_top_level_domain,
}),
}
Это нормально ... возвращает объект PersonalContact, заполненный как и ожидалось ... только он возвращает 3 из них! Я думал, что группировка в Контакте устранит дубликаты, но ... Нет.
Вот как выглядит результат (я только вставил один, но вернул три) ...
{
"FirstName": "Morgan",
"LastName": "Freeman",
"DOB": "1937-06-01T00:00:00",
"Prefix": "Mr",
"IsFemale": false,
"ID": 18,
"Label": "Personal Contact",
"Emails": [{
"ID": 12,
"LocalPart": "mfreeman",
"Domain": "hollywood",
"TopLevelDomain": "com",
"Category": "Personal",
"Preferred": true,
"Display": "mfreeman@hollywood.com"
},
{
"ID": 13,
"LocalPart": "morgan.freeman",
"Domain": "studiocity",
"TopLevelDomain": "net",
"Category": "Personal",
"Preferred": false,
"Display": "morgan.freeman@studiocity.net"
},
{
"ID": 14,
"LocalPart": "bob.smith",
"Domain": "gmail",
"TopLevelDomain": "com",
"Category": "Private",
"Preferred": false,
"Display": "bob.smith@gmail.com"
}],
}
Проблема только усугубляется, так как я добавляю несколько телефонов к контакту.
Любая помощь будет признательна!
ОБНОВЛЕНИЕ
Я думал стоило ответить на вопрос NetMage " Что такое qryContacts? Где вы фильтровали по адресу электронной почты? "
Я придумал следующую схему, которая позволяет мне определить LINQ-запрос динамически ... вроде. Я создаю переменную, которая содержит список выражений. Это позволяет мне добавлять любые критерии, которые я хочу во время выполнения.
var contactFilter = new List<Expression<Func<contact, bool>>>();
contactFilter.Add(e => e.emails.Where(x=>x.email_domain == "gmail").FirstOrDefault() != null);
Затем я получаю IQueryable, представляющий всю таблицу.
var qryContacts = ctx.contacts;
Теперь я добавляю содержимое фильтра в запрос.
if (contactFilter != null)
{
foreach (var item in contactFilter)
{
qryContacts = qryContacts.Where(item);
}
}
Затем запрос построен поверх этого, как показано в оригинальном сообщении. Надеюсь, это полезно. У него есть некоторые ограничения, но это был очень продуктивный шаблон для меня, облегчающий задачу написания запросов, когда вы точно не знаете, какие поля будут определены. Мое понимание основ Linq и Expressions очень ограничено, поэтому я обнаружил, что эту технику гораздо проще реализовать, чем некоторые из «Строителей». Что вы думаете об этой технике? Хотелось бы услышать некоторые отзывы.