LINQ:在多个jeft连接中导航时遇到问题

时间:2016-11-25 14:36:58

标签: c# sql asp.net entity-framework linq

我在SQL中尝试做的事情如下:

List<Criteria> criterias = new ArrayList<Criteria>();
...
while (matcher.find())
    {
        String key = matcher.group(1);
        String operator = matcher.group(2);
        String value = matcher.group(3);
        // get from map appropriate implementation
        criterias.add(expressions.get(operator).toCriteria(key, value));
    }

在Lead模型中:

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

在LeadContact模型中:

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

现在,我正在尝试从以下实例构建对象:

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

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

对于我的生活,我无法弄清楚如何导航到联系人表格。

leads = IQueryable<Lead>...

QuoteSearchItem.LeadSales是一个字符串。它必须是:

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

由于关系类型,l.LeadContacts.Contacts不是一个选项。

我需要做什么才能做到这一点?

4 个答案:

答案 0 :(得分:1)

您可以执行以下操作:

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

但是,您的Contact属性不是LeadContact类中的列表。因此,要么将其设为列表,要么可以像以下一样访问它:

l.LeadContacts.Select(x => x.Contact)

答案 1 :(得分:1)

如果你使用理解语法(当有多个froms时使用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中运行它,您可以获得lambda版本+,如果这是SQL本身的Linq To 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
               ....
              };

在(方法)lambda形式或理解语法中,最终结果相同。当需要selectMany时,我发现理解语法更容易。正如我所说,如果你正在为方法语法而死,那么试试在LinqPad中运行它,它会给你lambda对应的东西,比如:

var result = leads
   .SelectMany (
      l => l.LeadContacts.DefaultIfEmpty (), 
      (l, lc) => 
         new QuoteSearchItem
         {
            //... 
            LeadSales = lc.Contact.FirstName + " " + lc.Contact.LastName
         }
   );

答案 2 :(得分:1)

首先,您需要在 LeadContact 表中使用外键。我假设你的Lead表有一个LeadId字段:

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

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

表示潜在客户和潜在客户联系人之间的关系,它会将记录限制为您想要的记录。 LeadContact是一个交叉引用,因此我确信它已经有一个“LeadId”字段(或其他名称),它映射到Lead表中的Lead Id字段,因此请指明上述关系。

假设LeadSales的类型为IEnumerable<string>,您可以执行以下操作:

var results = leads.Select(l => new QuoteSearchItem
{
    ....
    LeadSales = l.LeadContacts.Select(lc => lc.Contact.FirstName + " " + lc.Contact.LastName);
    ....
});

答案 3 :(得分:0)

您使用的是上下文吗?

var result = await context.SearchLead.AsNoTracking()
.Where(l => l.LeadContacts.Any(lc => lc.Contact == QuoteSearchItem))
.ToListAsync();