简体   繁体   中英

Convert SQL query to LINQ method syntax

Can someone help me translate the following SQL query into a LINQ format → method syntax?

select Employees.Id,Positions.Name from Employees 
left join Contracts on Employees.Contract_id=Contracts.Id
left join Positions on Contracts.Position_Id=Positions.Id

One of the things I think people perhaps fail to appreciate when they come from SQL and start with LINQ and EF is just how much EF will do for them under the hood. They know what they know from an SQL perspective and the first thought is "I need a join b join c, so I need to use linq joins in C#" - maybe they find query syntax, maybe they write something that works and then wonder how to convert it to method syntax (not always a great idea; some stuff in linq is much neater as query syntax)

It's not necessary to be so intensely involved with EF though. If you have your client side entities set up so there are navigation properties between them:

//employee has a contract has a position
//positions has contracts has employees

public class Employee{
  public int Id{get;set;}
  public Contract Contract {get;set;}
}
public class Contract{
  public int Id{get;set;}
  public Position Position {get;set;}
  public ICollection<Employee> Employees {get;set;}
}
public class Position{
  public int Id{get;set;}
  public string Name {get;set;}
  public ICollection<Contract> Contracts {get;set;}
}

Then EF knows how entities and tables relate, so it's enough to simply say:

context.Employees.Select(r => new { e.Id, e.Contract.Position.Name } );

EF will do all the joins necessary to fetch the requested data. You don't need to pummel it into doing every join in the same way as SQL. It's an "object/relational mapper" - its job is to know about a set of objects over here, that looks like a bidirectionally linked tree where you can travel up and down branches using a . member access operator.. and a set of tables over there that maintain the data in the tree. It will watch you navigate the tree and form SQL to provide the data for the result

It isn't perfect or universally capable, but it's pretty good and knows some neat tricks (if you said contracts.Select(c => new { c, c.Employees.OrderByDescending(e => e.HireDate).First() }) for example, it'd script that up as a ROW_NUMBER() OVER(PARTITION BY employeeid ORDER BY hiredate DESC)..WHERE rn = 1 ) so for most common stuff that is within its capabilities you can stay in C# land and just let it get on with the translating. You'll find out quickly if you've reached its limits (it throw an exception for anything it can't translate)


Footnote:

I always wondered, having set up keys between tables etc why one could never just write an SQL like

SELECT e.Id, e.Contracts.Positions.Name
FROM e
WHERE ...

And travel along a relationship in a "towards the 1 end" direction automatically. Why did it always have to be so manual? Why is there seldom used near-useless carp like NATURAL JOIN and nothing to join on two columns that have a PK:FK relationship? But then when you read what DBAs have to say it becomes more clear that coders and DBAs view things slightly differently, and easier to see why they (and database developers) perhaps want to keep their very specific set ways, and why abstracting over them to provide auto join is something the coders would do at a different level

var data =
    from e in db.Employees
    join c in db.Contracts on e.Contract_id equals c.Contract_id
    join p in db.Positions on e.Position_Id equals p.Position_Id
    select new { Id = e.Id, Name = p.Name };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM