RichErp EfCore linq的正確寫法
RichErp EfCore linq的正確寫法
好多網友不知道ef 的linq 如何寫才能高效且簡潔,我總結了一下,歸納如下:
如: 從操作員表usergl_czy中獲取數據
1、得到一行數據
var czy1 = (from a in dbContext.usergl_czy
where a.czybm == "9999"
select a).FirstOrDefault();
對應的sql為:
SELECT TOP(1) [a].[czyid], [a].[bm], [a].[czy], [a].[czybm], [a].[dh], [a].[isallkehu], [a].[isrun], [a].[note]
WHERE [a].[czybm] = N‘9999‘
註意:有 Top 1
2、得到一組數據
var czy1 = (from a in dbContext.usergl_czy
where a.czybm.Contains("9999")
select a).ToList();
對應的sql為:
SELECT [a].[czyid], [a].[bm], [a].[czy], [a].[czybm], [a].[dh], [a].[isallkehu], [a].[isrun], [a].[note]
WHERE CHARINDEX(N‘9999‘, [a].[czybm]) > 0
註意:沒有 Top 1
2、外鍵關聯其他表,如獲取部門數據class_class
形式一:
var czy1 = (from a in dbContext.usergl_czy
join bb in dbContext.class_class
on a.bm equals bb.child into bbs
from b in bbs.DefaultIfEmpty()
where a.czybm == "9999"
select new
{
user = a,
part = b
}).ToList();
對應的sql為:
SELECT [a].[czyid], [a].[******], [bb].[child], [bb].[bm], [bb].[childname]
FROM [usergl_czy] AS [a]
LEFT JOIN [class_class] AS [bb] ON [a].[bm] = [bb].[child]
WHERE [a].[czybm] = N‘9999‘
註意:left join
形式二:
var czy1 = (from a in dbContext.usergl_czy
from b in dbContext.class_class.Where(x => x.child == a.bm).DefaultIfEmpty()
where a.czybm == "9999"
select new
{
user = a,
part = b
}).ToList();
對應的sql為:
SELECT [a].[czyid], [a].[bm],a.****** [略],[t0].[child], [t0].[childname]
FROM [usergl_czy] AS [a]
CROSS APPLY (
SELECT [t].[child], [t].[childname]
FROM (
SELECT NULL AS [empty]
) AS [empty]
LEFT JOIN (
SELECT [x].[child], [x].[childname]
FROM [class_class] AS [x]
WHERE [x].[child] = [a].[bm]
) AS [t] ON 1 = 1
) AS [t0]
WHERE [a].[czybm] = N‘9999‘
對應的sql有點復雜,感覺不如形式一簡潔。
部門表class_class中的數據可以缺失,但不影響獲取的主表數據
註意:DefaultIfEmpty(),CROSS APPLY,LEFT JOIN
3、內鍵關聯其他表,如獲取部門數據class_class
形式一:
var czy1 = (from a in dbContext.usergl_czy
join bb in dbContext.class_class
on a.bm equals bb.child into bbs
from b in bbs
where a.czybm == "9999"
select new
{
user = a,
part = b
}).ToList();
對應的sql為:
SELECT [a].[czyid], [a].******, [bbb].[child], [bbb].[bm], [bbb].[childname]
FROM [usergl_czy] AS [a]
INNER JOIN [class_class] AS [bbb] ON [a].[bm] = [bbb].[child]
WHERE [a].[czybm] = N‘9999‘
註意: inner join
形式二:
var czy1 = (from a in dbContext.usergl_czy
from b in dbContext.class_class.Where(x => x.child == a.bm)
where a.czybm == "9999"
select new
{
user = a,
part = b
}).ToList();
對應的sql為:
SELECT [a].[czyid], [a].[******], [x].[child], [x].[bm], [x].[childname]
FROM [usergl_czy] AS [a]
CROSS JOIN [class_class] AS [x]
WHERE ([x].[child] = [a].[bm]) AND ([a].[czybm] = N‘9999‘)
註意:沒有了DefaultIfEmpty(),CROSS JOIN代替了
4、in 的用法
string[] ids = new string[] { "0001","0002","0003"};
var czy1 = (from a in dbContext.usergl_czy
join bb in dbContext.class_class
on new { id = a.bm,id2=a.czyid } equals new { id = bb.child,id2=bb.childname } into bbs
from b in bbs
where ids.Contains(a.czybm)
select new
{
user = a,
part = b
}).ToList();
對應的sql為:
SELECT [a].[czyid], [a].[******], [bb].[child], [bb].[bm], [bb].[childname]
FROM [usergl_czy] AS [a]
INNER JOIN [class_class] AS [bb] ON ([a].[bm] = [bb].[child]) AND ([a].[czyid] = [bb].[childname])
WHERE [a].[czybm] IN (N‘0001‘, N‘0002‘, N‘0003‘)
註意:ids可以為List<string>。
5、獲取其他額外數據:
string[] ids = new string[] { "0001","0002","0003"};
var czy1 = (from a in dbContext.usergl_czy
join bb in dbContext.class_class
on new { id = a.bm } equals new { id = bb.child } into bbs
from b in bbs
where ids.Contains(a.czybm)
select new
{
user = a,
part = b,
roles = (from c in dbContext.usergl_czyrole
where c.czyid == a.czyid
select c) (.ToList())
}).ToList();
對應的sql為:
SELECT [a].[czyid], [a].[****], [bb].[child], [bb].[bm], [bb].[childname]
FROM [usergl_czy] AS [a]
INNER JOIN [class_class] AS [bb] ON [a].[bm] = [bb].[child]
WHERE [a].[czybm] IN (N‘0001‘, N‘0002‘, N‘0003‘)
註意:生成的sql裏面沒有usergl_czyrole,原來是sql server另外自動生成了sql語句,這樣,數據量大時,是不是很慢?
exec sp_executesql N‘SELECT [c].[czyid], [c].[roleid]
FROM [usergl_czyrole] AS [c]
WHERE [c].[czyid] = @_outer_czyid‘,N‘@_outer_czyid nvarchar(450)‘,@_outer_czyid=N‘0001‘
6、還可以這樣設計,在類外面再套一層,這樣靈活度大大提高:
var czy1 = (from a in dbContext.usergl_czy
join bb in dbContext.class_class
on new { id = a.bm } equals new { id = bb.child } into bbs
from b in bbs
where ids.Contains(a.czybm)
select new Usergl_czyExt
{
usergl_czy = a,
PartExt = new Class_classExt
{
class_class = b
}
}).ToList();
生成的sql命令沒有什麽不同。
註意:在efcore中這樣是允許的,但在.net framework中是不允許的。
public class Usergl_czyExt : RichErpEntityObject
{
public usergl_czy usergl_czy{get;set;}
public Class_classExt PartExt{get;set;}
}
最後,總結一個規律:
(1)、最好把您要獲取數據表放到第一行,其他表都用DefaultIfEmpty()關聯,這樣可能獲取的數據中主表是全的,不會遺漏。
(2)、形式一的linq較復雜,但生成的sql高效,形式二的linq簡潔,但生成的sql莫名其妙,但結果都一樣。
還是推薦用形式一吧
(3)、如果有涉及多列的where條件,可以這樣寫:
var czy1 = (from a in dbContext.usergl_czy
join bb in dbContext.class_class
on new { id = a.bm,id2 = a.bm2 } equals new { id = bb.child,id2 = bb.child2 } into bbs
from b in bbs
where a.czybm == "9999"
select new
{
user = a,
part = b
}).ToList();
(4)、直接對數據庫操作的linq,裏面的where條件是有限的,對於List<T>的linq,where條件是沒有限制的,用什麽函數都行。
RichErp EfCore linq的正確寫法