我需要加入两个对象(表格)A和B.对于任何A,可以有零到多个B。查询需要每A返回一行。
我希望在加入之前订购B,以便能够在某个条件下从B中选择所需的行。说B有一个列类型。如果存在类型1那么那就是我需要的B,否则:必须选择类型2等。
现在我考虑一下,即使在T-sql中我也不确定如何做到这一点。 我想是这样的:
SELECT A.*
FROM A LEFT JOIN (
SELECT * FROM B AS B1 WHERE B1.Type = (SELECT TOP 1 B2.Type FROM B AS B2
WHERE B2.JoinID = B1.JoinID
ORDER BY B2.Type )
) AS B ON B.JoinID = A.JoinID
[编辑]
在sgtz的回答中,我试图让它发挥作用。如果必须再做一步,因为我想订购的字段不存在。我在步骤1中添加了这个字段,在步骤2中我选择了键并在步骤3中加入了所有内容,但是我收到一个错误“join子句中某个表达式的类型不正确。类型推断失败了打电话给'GroupJoin'。“加入“加入adressen1 on new {b.TopRelatieID ...”
var adressen1 = from a in db.Adres
select new
{
RelatieAdres = a,
Sortering = (int)(a.AdresType.Code == codeVestAdres ?
1 : a.AdresType.Code == codePostAdres ?
2 : (100 + (int)a.AdresType.Code.ToCharArray()[0]))
};
var adressen2 = from b in adressen1
group b by new { RelatieID = b.RelatieAdres.RelatieID } into p
let TopAdresType = p.Min(at => at.Sortering)
select new { TopRelatieID = p.Key.RelatieID, TopAdresType };
var q = from k in db.Klants
join b in adressen2 on k.RelatieID equals b.TopRelatieID into b_join
from b in b_join.DefaultIfEmpty()
join a in adressen1 on new { b.TopRelatieID, b.TopAdresType } equals new { a.RelatieAdres.RelatieID, a.Sortering } into a_join
from a in a_join.DefaultIfEmpty()
答案 0 :(得分:0)
为了有意义,你应该至少添加一些东西来查询结果,而不仅仅是A. *。否则,您将获得A的副本,其中某些行可能重复。如果我正确理解了这个问题,那么这个SQL查询应该可以工作:
SELECT DISTINCT A.*, B.Type
FROM A LEFT JOIN
(SELECT TOP (1) JoinID, Type
FROM B
ORDER BY Type
GROUP BY JoinID, Type
) AS B ON A.JoinID = B.JoinID
转换为LINQ,它是(更新)
(from a in As
join b in
(from b1 in Bs
orderby b1.Type
group b1 by b1.JoinID into B1
from b11 in B1
group b11 by b11.Type into B11
from b111 in B11
select new { b111.JoinID, b111.Type }).Take(1)
on a.JoinID equals b.JoinID into a_b
from ab in a_b.DefaultIfEmpty()
select new { a_b.JoinID, /*all other a properties*/ a_b.Type }).Distinct()
LINQ可能无法正常工作,但您应该抓住这个想法。
答案 1 :(得分:0)
这是一个有效的例子。我做了两个阶段。
[Test]
public void Test333()
{
List<Order> O;
var M = Prepare333Data(out O);
var OTop = from o in O
group o by new {id=o.id, orderid=o.orderid}
into p
let topType = p.Min(tt => tt.type)
select new Order(p.Key.id, p.Key.orderid, topType);
var ljoin = from m in M
join t in OTop on m.id equals t.id into ts
from u in ts.DefaultIfEmpty()
select new {u.id, u.orderid, u.type};
}
public class Manufacturer
{
public Manufacturer(int id, string name)
{
this.id = id;
this.name = name;
}
public int id { get; set; }
public string name { get; set; }
}
public class Order
{
public Order(int id, int orderid, int type)
{
this.orderid = orderid;
this.id = id;
this.type = type;
}
public int orderid { get; set; }
public int id { get; set; }
public int type { get; set; }
}
private List<Manufacturer> Prepare333Data(out List<Order> O)
{
var M = new List<Manufacturer>() {new Manufacturer(1, "Abc"), new Manufacturer(2, "Def")};
O = new List<Order>()
{
new Order(1, 1, 2),
new Order(1, 2, 2),
new Order(1, 2, 3),
new Order(2, 3, 1)
,
new Order(2, 3, 1)
,
new Order(2, 3, 2)
};
return M;
}
对评论的回应:
你的“new {”会创建一个新的匿名类型。如果类型以相同的顺序声明并且它们具有相同的类型定义(即int匹配int,而不是int匹配short),则由差异进程创建的两个匿名类型被称为具有相同的签名。我没有在LINQ中广泛测试这种情况。
这就是为什么我使用真正的具体类,而不是JOIN部分中的anon类型。可能有一种方法可以用纯LINQ重做它,但我不知道它是什么还是。如果它发生在我身上,我会给你回复。
我建议现在也使用具体课程 即代替
*new {*
进行连接时,请始终使用
*new CLASSNAME(){prop1="abc",prop2="123"*
它有点长,但更安全......至少在我们弄清LINQ内部的内容之前更安全。