[英]Linq query with multiple subqueries
我正在将 Oracle Sql 查询转换为 Linq,但不确定如何继续。 这是 Sql 查询:
SELECT *
FROM CustomerShip,
(SELECT DISTINCT b.ShipSeq AS shipSeq
FROM Orders a,
CustomerShip b
WHERE a.OrderId IN (SELECT OrderId
FROM Orders
WHERE CustomerId = @CustomerId
AND OrderType <> 'A')
AND b.CustomerId = @CustomerId
AND b.ShipSeq = a.CustShip
AND OrderStatus <> 'C'
GROUP BY b.ShipSeq) i
WHERE CustomerId = @CustomerId
AND (Address NOT LIKE '%RETAIL%STORE%')
AND ShipSeq = i.ShipSeq(+)
ORDER BY ShipTo DESC, OrderDate DESC;
在转换为 linq 时,我试图将其分解为三个单独的查询。
var query1 = from c in CustomerShip
where c.CustomerId == customerId
&& !c.Address.Contains("RETAIL")
&& !c.Address.Contains("STORE")
orderby c.ShipTo descending, c.OrderDate descending
select c;
var query2 = from o in Orders
where o.CustomerId == customerId
&& !o.OrderType.Equals("A")
select o.OrderId;
var query3 = (from o in Orders
from c in CustomerShip
where c.CustomerId == customerId
&& c.ShipSeq == o.CustShip
&& !o.OrderStatus.Equals("A")
select c.ShipSeq).Distinct();
现在我试图将它们全部组合成一个查询,但不确定如何去做。 这是我要去的方向:
var query = from c in CustomerShip
let subquery = from o in Orders
where o.CustomerId == customerId
&& !o.OrderType.Equals("A")
select o.OrderId
from or in model.Orders
where subquery.Contains(or.OrderId)
&& c.CustomerId == customerId
&& c.ShipSeq == or.CustShip
&& !or.OrderStatus.Equals("A")
group c by c.ShipSeq
into i
select c.ShipSeq
where c.CustomerId == customerId
&& !c.Address.Contains("RETAIL")
&& !c.Address.Contains("STORE")
orderby c.ShipTo descending, c.OrderDate descending
select c, i;
更新
我有一个类型有效的查询,但它需要将近两分钟来执行(与 Oracle 查询的 0.02 秒相比)并且结果的顺序不正确。 有人看到我缺少什么吗?
var innerQuery = from x in model.Orders
where x.CustomerId == customerId
&& !x.OrderType.Equals("A")
select x.OrderId;
var result = from c in model.CustomerShip
join subQuery in
(
(from o in model.Orders
from c in model.CustomerShip
where c.CustomerId == customerId
&& innerQuery.Contains(o.OrderId)
&& !o.FLAG_ORD_STATUS.Equals("C")
&& c.ShipSeq == o.CustShip
select c.ShipSeq).Distinct()
) on c.ShipSeq equals subQuery into temp
from x in temp.DefaultIfEmpty()
where c.CustomerId == customerId
&& !c.Address.Contains("RETAIL")
&& !c.Address.Contains("STORE")
orderby c.ShipTo descending, c.OrderDate descending
select c;
请记住,您只是在此处构建查询。 在您执行ToList()
或.FirstOrDefault()
或其他任何操作之前,不会执行任何操作。 SO,您可以在其他查询中使用这些查询,并且在执行时会创建一个大 SQL 语句。
var query2 = from o in Orders
where o.CustomerId == customerId
&& !o.OrderType.Equals("A")
select o.OrderId;
var query3 = (from o in Orders
join c in CustomerShip on o.CustShip equals c.ShipSeq
where c.CustomerId == customerId
&& !o.OrderStatus.Equals("A")
&& query2.Contains(o.OrderId)
select c.ShipSeq).Distinct();
var query1 = from c in CustomerShip
from i in query3
where c.CustomerId == customerId
&& !c.Address.Contains("RETAIL")
&& !c.Address.Contains("STORE")
&& c.ShipSeq == i.ShipSeq
orderby c.ShipTo descending, c.OrderDate descending
select c;
但是,我很确定您可以将 query2 和 query3 减少到仅:
var query3 = (from o in Orders
join c in CustomerShip on o.CustShip equals c.ShipSeq
where c.CustomerId == customerId
&& !o.OrderStatus.Equals("A")
&& !o.OrderType.Equals("A")
select c.ShipSeq).Distinct();
尝试这样的事情。 我为一些类建模只是为了消除错误。 如果您按 ShipSeq 分组,则不需要不同。 只需从组中取出第一项就会得到相同的结果。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace ConsoleApplication60
{
class Program
{
static void Main(string[] args)
{
int customerID = 1234;
List<Order> CustomTypeA = Order.orders
.Where(x => (x.CustomerId == customerID) && (x.OrderType == "A") && (x.OrderStatus == "C")).ToList();
var results = (from CustA in CustomTypeA
join CustShip in Ship.CustomerShip on CustA.CustomerId equals CustShip.CustomerId
select new { CustA = CustA, CustShip = CustShip})
.Where(x => (!RetailStore(x.CustShip.Address)) && (x.CustA.CustShip == x.CustShip.ShipSeq))
.OrderByDescending(x => x.CustShip.OrderDate)
.GroupBy(x => x.CustShip.ShipSeq)
.Select(x => x.FirstOrDefault())
.Select(x => new {
CustomerID = x.CustShip.CustomerId,
Address = x.CustShip.Address,
OrderDate = x.CustShip.OrderDate
}).ToList();
}
static Boolean RetailStore(string address)
{
string pattern = "RETAIL.*STORE";
return Regex.IsMatch(address, pattern);
}
}
public class Order
{
public static List<Order> orders = new List<Order>();
public int CustomerId { get; set; }
public string OrderType { get; set; }
public string CustShip { get; set; }
public string OrderStatus { get; set; }
}
public class Ship
{
public static List<Ship> CustomerShip = new List<Ship>();
public int CustomerId { get; set; }
public string ShipSeq { get; set; }
public string Address { get; set; }
public DateTime OrderDate { get; set; }
}
}
query2 和 query3 在此处合并为内部查询
var Innerquery = (from o in Orders
join c in CustomerShip on o.CustShip equals c.ShipSeq
where c.CustomerId == customerId
&& !o.OrderStatus.Equals("A")
&& !o.OrderType.Equals("A")
select c.ShipSeq).Distinct();
var query1 = from c in CustomerShip
from i in query3
where c.CustomerId == customerId
&& innerquery.Contains(c.CustomerId)
&& !c.Address.Contains("RETAIL")
&& !c.Address.Contains("STORE")
&& c.ShipSeq == i.ShipSeq
orderby c.ShipTo descending, c.OrderDate descending
select c;
或者你可以试试 Linqer http://www.sqltolinq.com
您的查询在 EF 中变慢的原因可能有很多 - 我建议使用分析器。
可能的原因是 EF 创建了一个低效的查询(通常数据库应该创建它自己的优化,但我在 EF 和 Oracle 方面有过糟糕的经历),或者,根据它加载的结果数量,将其映射到实际对象非常昂贵.
一般来说,虽然在 .NET 世界中似乎不是一个流行的观点,但我建议创建一个视图,或者在有复杂查询时使用dbcontext.Database.SqlQuery<CustomerShip>(sql)
,尤其是在使用 Oracle 时,至少根据我过去的经验(已经有一段时间了,所以我可能是错的。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.