1. 程式人生 > >RichErp EfCore linq的正確寫法

RichErp EfCore linq的正確寫法

net .class 如果 自動 多列 oss 最好 cor note

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]

  FROM [usergl_czy] AS [a]
  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]

  FROM [usergl_czy] AS [a]
  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的正確寫法