SQL 转换为 Linq to entities

SQL conversion to Linq to entities

SQL请求:

DECLARE @search varchar(20)
set @search = '%a%'

Select distinct top (500) 
    Customer.Number,Contact.name, Address.StreetAddress, Phone.Number, 
    Customer.Type               
from 
    Customer
left join 
    dbo.Address on dbo.Customer.ContactId  = dbo.Address.ContactId
left join 
    dbo.Contact on dbo.Customer.ContactId  = dbo.Contact.Id
left join 
    dbo.Phone on dbo.Customer.ContactId  = dbo.Phone.ContactId 
              and Phone.Sequence = 1
where 
    Customer.IsActive = 1 
    and Customer.ContactId 
        in (--Primary Contact
            SELECT  Customer.ContactId
            FROM dbo.Customer
            INNER JOIN dbo.Contact ON dbo.Contact.id = dbo.Customer.ContactId
            LEFT JOIN dbo.Email ON dbo.Customer.ContactId  = dbo.Email.ContactId
            LEFT JOIN dbo.Phone ON dbo.Customer.ContactId  = dbo.Phone.ContactId
            LEFT JOIN dbo.Address ON dbo.Customer.ContactId  = dbo.Address.ContactId
            WHERE 
                Contact.FirstNameCareOf LIKE @search
                OR Contact.Name LIKE @search
                OR Email.Address LIKE @search
                OR Phone.Number LIKE @search
                OR Address.StreetAddress LIKE @search
                OR Address.City LIKE @search
                OR Address.ZipCode LIKE @search

          union

          --Secondary Contacts
          SELECT Customer.ContactId
          FROM dbo.Customer
          INNER JOIN dbo.Relationship ON dbo.Contact.Id = dbo.Relationship.TargetContactId
          INNER JOIN dbo.Contact on dbo.Contact.id = dbo.Relationship.SourceContactId
          LEFT JOIN dbo.Email ON dbo.Contact.Id = dbo.Email.ContactId
          LEFT JOIN dbo.Phone ON dbo.Contact.Id = dbo.Phone.ContactId
          WHERE 
            Contact.FirstNameCareOf LIKE @search
            OR Contact.Name LIKE @search
            OR Email.Address LIKE @search
            OR Phone.Number LIKE @search)
order by
    Customer.Number

这是我目前得到的:

from customerTable in Customers

    join contactTable in Contacts
        on customerTable.ContactId equals contactTable.Id

    join addressTable in Addresses
        on customerTable.ContactId equals addressTable.ContactId

    // the following may no exists for the customer so we dont want to join them since the customer will not be in the request results because of this  
    //  join phoneTable in Phones
    //      on customerTable.ContactId equals phoneTable.ContactId 
    //      
    //  join emailTable in Emails
    //      on customerTable.ContactId equals emailTable.ContactId

    // alternate method to query email and phone table without effecting the results    
    let emailMatch = Emails.Where (p => p.ContactId == customerTable.ContactId && p.Address.Contains("a"))
    let phoneMatch = Phones.Where (p => p.ContactId == customerTable.ContactId && p.Number.Contains("a"))

    where customerTable.IsActive && ( contactTable.Name.Contains("a") || contactTable.FirstNameCareOf.Contains("a") ||addressTable.StreetAddress.Contains("a") || addressTable.City.Contains("a") ||    
                                          addressTable.ZipCode.Contains("a") || emailMatch.Any()|| phoneMatch.Any() )
 orderby customerTable.Number 
            select new {CustomerNumber = customerTable.Number, contactTable.Name, addressTable.StreetAddress, customerTable.Type.EnumId}

问题

  1. 有没有一种简单的方法可以将我的 SQL 请求转换为 linq 到实体?一天后我仍然在玩上面的 linq 请求

  2. 在我的 SQL 请求中执行内部联接和左联接的真正和最有效的方法是什么?

  3. 尝试将 EXACT SQL 请求 "statement" 转换为 linq 是否有意义?还是在 linq 中使用完全不同的方法更好?我的意思是在 SQL 中执行此操作的最高效方法在 linq?

  4. 中不一定完全相同
  5. 当取消对 phones 的连接的注释时....它不会 return 任何没有 phone 的客户...是否可以 return 即使在 phone table 上没有任何内容可以加入该客户?

感谢您的帮助或任何开始。

看来您可以只使用您正在搜索的 4 个实体并合并结果。

这是一个相当大的查询,但您可以使用它作为起点。

var contacts = from c in Contacts
               where c.FirstNameCareOf.Contains("c") ||
                     c.Name.Contains("c")
               select c.Customer;

var emails =   from e in Emails
               where e.Address.Contains("c")
               select e.Contact.Customer;

然后,当您拥有所有客户后,只需将他们添加到列表中即可。

var customers = new List<Customer>();
customers.AddRange(contacts);
customers.AddRange(emails);
etc..

你的前三个问题的答案是:使用导航属性。 出于某种原因,具有 SQL 背景的人几乎总是从 [=13= 开始编写 LINQ ] 声明。这至少有三个主要缺点: join 语句 -

  • 冗长
  • 不揭示关联的多重性。声明

    from customerTable in Customers
    join contactTable in Contacts ...
    

    没有告诉我客户联系人是 1-nn-1 还是 1-1

  • 容易出错:您必须输入连接列,而且您可能会选择错误的列(我见过这种情况)。

如果您使用正确命名的导航属性,这一切都会改变,例如

from cust in Customers
from cont in cust.Contacts ...

很短,表明关联是1-n,你配置一次关联,再也不用关心连接列了。

所以如果你这样做,你的查询将被塑造成

from cust in Customers
where cust.Contacts
          .Any(cont => cont.Name.Contains("a")
                    || cont.FirstNameCareOf.Contains("a")
                    || cont.Address.StreetAddress.Contains("a")
                    || cont.Address.City.Contains("a")
                    || ...  )
   || cust.Relationships
          .Any(rel => rel.TargetContact.Name.Contains("a")
                   || rel.TargetContact.FirstNameCareOf.Contains("a")
                   || rel.TargetContact.Address.StreetAddress.Contains("a")
                   || rel.TargetContact.Address.City.Contains("a")
                   || ...  )
select cust

(如你所见,我不得不猜测客户关系的多样性)

这将生成一个 SQL 查询,其中主要谓词由 EXIST 语句组成。我认为这比 INDISTINCT 的组合更好,因为 EXIST 是一种有效的搜索策略。

关于您的第四个问题:您还可以在查询中包括手机上的匹配项,以及 || cont.Phone == null