То, что я пытаюсь сделать в SQL, выглядит так:

SELECT
    ....
    ct.FirstName + ' ' + ct.LastName
    ....
FROM
    Leads l
    LEFT JOIN LeadContacts lc ON lc.LeadID = l.LeadID 
    LEFT JOIN Contacts ct on ct.ContactID = lc.ContactID

В модели Lead:

public class Lead
{
    ....
    public virtual ICollection<LeadContact> LeadContacts { get; set; }
    ....
}

А в модели LeadContact:

public class LeadContact
{
    ....
    [ForeignKey(nameof(LeadID))]
    public virtual Lead Lead { get; set; }

    [ForeignKey(nameof(ContactID))]
    public virtual Contact Contact { get; set; }
    ....
}

А теперь я пытаюсь построить объект из экземпляра:

leads = IQueryable<Lead>...

И хоть убей, я не могу понять, как перейти к таблице контактов.

var results = leads.Select(l => new QuoteSearchItem
{
    ....
    SomeProperty = l.SomeProperty,
    LeadSales = l.LeadContacts. ?????
    SomeOtherProperty = l.SomeOtherProperty
    ....
 });

QuoteSearchItem.LeadSales - это строка. Это должно быть:

Contacts.FirstName + " " + Contacts.LastName

Из-за типа отношения l.LeadContacts.Contacts не подходит.

Что мне нужно сделать, чтобы это стало возможным?

1
Casey Crookston 25 Ноя 2016 в 17:36

4 ответа

Лучший ответ

Вы можете сделать это легко, если используете синтаксис понимания (который использует SelectMany, когда есть несколько исходных):

var query = from l in Leads
            from lc in l.LeadContacts.DefaultIfEmpty()
            from ct in lc.Contacts.DefaultIfEmpty()
            select new
            {
               //....
               ContactName = ct.FirstName + ' ' + ct.LastName
               //....
            };

И если вы хотите, запустив это в LinqPad, вы можете получить версию лямбда +, если это Linq To SQL, сам SQL.

РЕДАКТИРОВАТЬ: ваш класс подразумевает, что для каждого LeadContact существует один контакт, тогда вы можете сократить это:

var query = from l in Leads
            from lc in l.LeadContacts.DefaultIfEmpty()
            select new
            {
                //....
                ContactName = lc.Contact.FirstName + ' ' + lc.Contact.LastName
                //....
            };

Он почти соответствует этому образцу, который использует образец базы данных Northwind:

var data = from c in Customers
               from o in c.Orders.DefaultIfEmpty()
               select new {
                 CustomerId = c.CustomerID,
                 OrderId = (int?)o.OrderID,
                 Employee = o.Employee.FirstName + ' ' + o.Employee.LastName
               };

Что дает этот SQL:

-- Region Parameters
DECLARE @p0 NChar(1) = ' '
-- EndRegion
SELECT [t0].[CustomerID] AS [CustomerId], [t1].[OrderID] AS [OrderId], ([t2].[FirstName] + @p0) + [t2].[LastName] AS [Employee]
FROM [Customers] AS [t0]
LEFT OUTER JOIN [Orders] AS [t1] ON [t1].[CustomerID] = [t0].[CustomerID]
LEFT OUTER JOIN [Employees] AS [t2] ON [t2].[EmployeeID] = [t1].[EmployeeID]

РЕДАКТИРОВАТЬ: То, что я говорил, вместо:

var results = leads.Select(l => new QuoteSearchItem
{
    ....
    LeadSales = l.LeadContacts. ?????
    ....
});

Сделай это как:

var results = from l in leads 
              from lc in l.LeadContacts.DefaultIfEmpty() 
              select new  QuoteSearchItem
              {
                ....
                LeadSales = lc.Contact.FirstName + " " + lc.Contact.LastName
               ....
              };

Либо в форме лямбда (метода), либо в синтаксисе понимания, конечный результат будет таким же. Когда требуется selectMany, я считаю, что синтаксис понимания проще. И, как я уже сказал, если вы умираете от синтаксиса метода, попробуйте запустить его в LinqPad, и он даст вам лямбда-аналог, что-то вроде:

var result = leads
   .SelectMany (
      l => l.LeadContacts.DefaultIfEmpty (), 
      (l, lc) => 
         new QuoteSearchItem
         {
            //... 
            LeadSales = lc.Contact.FirstName + " " + lc.Contact.LastName
         }
   );
1
Cetin Basoz 25 Ноя 2016 в 15:39

Прежде всего, вам понадобится внешний ключ в таблице LeadContact . Я предполагаю, что в вашей таблице Lead есть поле LeadId:

//Foreign key for Standard
public int LeadId { get; set; }

[ForeignKey("LeadId")]
public Lead Lead { get; set; }

Это представляет отношения между лидом и контактом, и это ограничивает записи теми, которые вы хотите. LeadContact - это перекрестная ссылка, поэтому я уверен, что у него уже есть поле «LeadId» (или какое-то другое имя), которое сопоставляется с полем Lead Id в таблице Lead, поэтому укажите эту связь, как показано выше.

Предполагая, что LeadSales имеет тип IEnumerable<string>, вы можете:

var results = leads.Select(l => new QuoteSearchItem
{
    ....
    LeadSales = l.LeadContacts.Select(lc => lc.Contact.FirstName + " " + lc.Contact.LastName);
    ....
});
1
JuanR 25 Ноя 2016 в 15:37

Вы могли бы сделать что-то вроде:

l.LeadContacts.SelectMany(x => x.Contacts)

Но ваше свойство Contact не является списком внутри вашего класса LeadContact. Так что либо составьте список, либо вы можете получить к нему доступ, например:

l.LeadContacts.Select(x => x.Contact)
1
Divyang Desai 25 Ноя 2016 в 16:19

Вы используете контексты?

var result = await context.SearchLead.AsNoTracking()
.Where(l => l.LeadContacts.Any(lc => lc.Contact == QuoteSearchItem))
.ToListAsync();
0
AJ_ 25 Ноя 2016 в 14:50