这个 SQL 语句在 Linq 中的等价语句是什么?

4

我需要将这个SQL语句转换为LINQ:

SELECT f.ID as IdFlight, 
       Tarif * 1 as Tarif, 
       f.Time, f.TimeOfArrival, 
       sl.Name as FromLoc, 
       sl.Country as FromCountry, 
       sl.Airport as FromAirport,
       dl.Name as ToLoc, 
       dl.Country as ToCountry, 
       dl.Airport as ToAirport 
FROM Flights as f 
    INNER JOIN Locations as sl ON sl.ID = f.ID_Source  
    INNER JOIN Locations as dl ON dl.ID = f.ID_Destination 
    INNER JOIN FlightsTarifs as ftf ON f.Id = ftf.IDFlight 
WHERE f.ID_Destination =30005 AND f.Time <= DATEADD(day,4,'2018/05/24 00:00') 
AND f.Time >= '2018/05/24 00:00' ORDER By f.Time, Tarif

我在 Linq 中的尝试:

IQueryable qinfo = from f in context.Flights
                   join sl in context.Locations on f.Id_Source equals sl.ID
                   join dl in context.Locations on f.Id_Destination equals dl.ID
                   join ftf in context.FlightsTarifs on f.ID equals ftf.IDFlight
                   where (f.Id_Source == aFormUser.FlightSrcID)
                   where (f.Id_Destination == aFormUser.FlightDestID)
                   where (f.Time.Date >= aFormUser.DepartureDate.Date)
                   where (f.Time.Date <= aFormUser.DepartureDate.Date.AddDays(4))
                   orderby f.Time, ftf.Tarif
                   select new {f.ID, ftf.Tarif, f.Time, f.TimeOfArrival,
                               sl.Name, sl.Country, sl.Airport,
                               dl.Name, dl.Country, dl.Airport  };

我现在有一些问题需要解决:

  1. 由于我在将航班表与位置表两次连接,以获取出发地和目的地位置的名称,在 LinQ 中这样做会导致编译器错误。错误信息显示 dl.Name、dl.Country、dl.Airport 是匿名类型,并且它们将与 sl.Name、sl.Country、sl.Airport 相同。
  2. 我不能像 SQL 中那样使用 "As" 表达式,LinQ 中是否有等价的表达式?
  3. 在 LinQ 查询中无法将 Tarif 乘以旅客数量,因为它不允许我这样做。

1
我会问你为什么想把完好的SQL代码转移到应用层。为什么不把你的查询语句转换成存储过程,并将应用程序中的层进行分离?对我来说,这似乎是迁移SQL代码的错误方向。 - Sean Lange
1
我正想写一个像Sean一样的评论。我完全同意他的观点。这样的查询必须留在存储过程中,将它们带到应用程序层是某种反模式。 - Mo Chavoshi
我必须将它移动到存储过程中吗?因为这是一个复杂的查询,无法使用linq完成。我不明白这会破坏什么模式。在复杂的应用程序中,您必须执行一些查询,难道每次在MVC中执行查询都违反了模式吗?此外,我不确定是否可以从MVC中使用存储过程。DBContext会负责调用任何存储过程吗?我需要进行EF Migration吗? - user1238784
我并不是在暗示任何模式被打破了。我是说,分层应用程序从长远来看更易于维护,其中之一就是数据层。实现这个意味着您的数据操作需要从应用程序中移除。从查询到linq的转变意味着您的数据操作与应用程序更紧密地耦合。这是一篇讨论分层的高级文章。https://learn.microsoft.com/zh-cn/previous-versions/msp-n-p/ee658109(v=pandp.10) - Sean Lange
反模式并不意味着打破模式,根据维基百科的定义,它是指一种常见的对于经常出现的问题的应对方式,通常是无效的,并且可能会产生高度逆效果。正如Sean所提到的,这只是一个建议,并不意味着你正在违反规则,但是更清晰的分层是一个好的实践。 - Mo Chavoshi
显示剩余5条评论
2个回答

3
您可以使用以下代码的别名与new对象初始化程序,这也支持对tarif进行倍增:
select new {
    f.ID,
    Tarif = ftf.Tarif * 1, // Alias and multiply by your number
    f.Time,
    f.TimeOfArrival,
    SourceName = sl.Name, // Alias
    SourceCountry = sl.Country, // Alias
    SourceAirport = sl.Airport, // Alias
    DestName = dl.Name, // Alias
    DestCountry = dl.Country, // Alias
    DestAirport = dl.Airport // Alias
};

只是提供更多细节以防其他人遇到这个问题,根本原因是代码使用new关键字来定义一个匿名类型,该匿名类型包含一个对象初始化程序,并且在尝试定义匿名类时遇到了多个冲突(具有相同推断名称的多个属性,然后在tarif被乘以时无法从表达式中命名属性)。
通过显式命名具有冲突的属性,编译器不再需要推断生成冲突的名称。
更多信息:http://geekswithblogs.net/BlackRabbitCoder/archive/2012/06/21/c.net-little-wonders-the-joy-of-anonymous-types.aspx 上面的链接提供了一些示例,说明如何在匿名类型中使用对象初始化程序。

1
这个概念被称为“投射”,您需要根据需求选择新的匿名类型或别名。
示例:
var result = data.Select( x => new { FieldName = x.Property } );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接