【问题标题】:What is the equivalent of this SQL statement in Linq?Linq 中这条 SQL 语句的等价物是什么?
【发布时间】:2018-05-24 14:22:36
【问题描述】:

我需要将此 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 查询中时,我无法将关税乘以乘客人数,但它不允许我这样做。

【问题讨论】:

  • 我想问你为什么要采用完美的sql并将其移动到应用程序层。为什么不将您的查询变成一个存储过程并在您的应用程序中分离这些层呢?对我来说,这似乎是迁移 sql 代码的错误方向。
  • 我正想写一个像肖恩这样的评论。我完全同意他的看法。这样的查询必须保留在存储过程中,并将它们带到应用层是某种反模式。
  • 我是否必须将其移动到存储过程,因为它是一个复杂的查询并且不能使用 linq 完成?我不明白这是如何打破这种模式的。您必须在复杂的应用程序中进行一些查询,您的意思是每次在 MVC 中执行查询时都会违反该模式?除此之外,我不确定是否可以使用 MVC 中的存储过程。 DBContext 会负责调用任何存储过程吗?我是否必须进行 EF 迁移才能这样做?
  • 我并不是说任何模式都被破坏了。我是说分层应用程序从长远来看更受支持,其中一个层是数据层。要做到这一点,您的数据操作需要从应用程序中删除。从查询转移到 linq 意味着您的数据操作与应用程序的耦合更加紧密。这是一篇很棒的文章,讨论了高层次的分层。 docs.microsoft.com/en-us/previous-versions/msp-n-p/…
  • 反模式并不意味着打破模式,根据维基百科,它意味着:反模式是对反复出现的问题的常见反应,通常是无效的,并且可能会适得其反。同样,正如 Sean 所说,这只是一个建议,并不意味着您违反了规则,但更清晰的分层是一个很好的做法。

标签: c# sql sql-server linq


【解决方案1】:

您可以将别名与 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

上面的链接有一些关于如何将对象初始化器与匿名类型一起使用的附加示例。

【讨论】:

    【解决方案2】:

    这个概念叫做Projection,你必须根据你的要求选择新的匿名类型或别名。

    示例:

    var result = data.Select( x => new { FieldName = x.Property } );
    

    【讨论】:

      猜你喜欢
      • 2021-11-17
      • 1970-01-01
      • 1970-01-01
      • 2013-02-24
      • 2018-04-15
      • 2011-01-26
      • 1970-01-01
      • 2012-03-22
      • 2018-01-21
      相关资源
      最近更新 更多