码迷,mamicode.com
首页 > 其他好文 > 详细

RichErp EfCore linq的正确写法

时间:2021-01-22 12:27:01      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:last   排除   day   元素   ice   国家   def   intersect   莫名其妙   

好多网友不知道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

 

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.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

4、内键关联其他表,如获取部门数据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代替了

 

5、in 和 not 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>。

not in 就在 ids.Contains(a.czybm)前面加一个!好了,where !ids.Contains(a.czybm)

 

 6、获取其他额外数据:

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‘

 7、还可以这样设计,在类外面再套一层,这样灵活度大大提高:

 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;}

}

 

如果表中列太多,全部获取没有必要,提取表中部分列:

var ss = (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
  select new Usergl_czyExt
  {
    usergl_czy = new usergl_czy
    {
      czyid = a.czyid,
      czybm = a.czybm
    },
    PartExt = new Class_classExt
    {
      class_class = new class_class
      {
        child = b.child,
        childname = b.childname
      }
    }
  }).ToList();

var ss = (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
  select new
  {
    usergl_czy = new
    {
      czyid = a.czyid,
      czybm = a.czybm
    },
    class_class = new
    {
      child = b.child,
      childname = b.childname
    }

  }).ToList();

对应的sql为:

SELECT [a].[czyid], [a].[czybm], [bb].[child], [bb].[childname]
FROM [usergl_czy] AS [a]
INNER JOIN [class_class] AS [bb] ON [a].[bm] = [bb].[child]

非常简洁。

 

 8、group by 统计每个部门的员工数量:

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.DefaultIfEmpty()
  group b by new { b.child, b.childname } into g
  select new
  {
    partId = g.Key.child,
    partName = g.Key.childname,
    count = g.Count()
  }).ToList();

对应的sql为:

SELECT [a0].[czyid], [a0].[*****], [bb0].[child], [bb0].[bm], [bb0].[childname]
FROM [usergl_czy] AS [a0]
LEFT JOIN [class_class] AS [bb0] ON [a0].[bm] = [bb0].[child]
ORDER BY [a0].[bm]

注意:郁闷,没有group by,不是.net core 2.1.1号称有了吗?还是没写对?有那么难吗?

获取的字段一个不少,但它自己加了一个order by,估计是方便把数据进行分组汇总。

 

 9、distinct

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
  select new
  {
    b.child,
    b.childname
  }).Distinct().ToList();

对应的sql为:

SELECT DISTINCT [bb].[child], [bb].[childname]
FROM [usergl_czy] AS [a]
INNER JOIN [class_class] AS [bb] ON [a].[bm] = [bb].[child]

虽然linq很啰嗦,但sql很高效哎!这样才对。

 

10、sum,count 等就比较简单了

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
  select a.mmdays).Sum();

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
  select a).Sum(x=>x.mmdays);

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
  select a).Count();

 注意:如果想这样:

.....

select new

{

  countValue = Count(x=>x.aaa),

  sumValue = Sum(x=>x.bbb)

}

 怎么办呢?

 

11、let

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
  let shortname = a.czyid.Substring(0, 4)

  let lowername = a.czy.ToLower()
  where shortname == "9999" && lowername == "abc"
  select new
  {
    a,
    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]
WHERE SUBSTRING([a].[czyid], 1, 4) = N‘9999‘ AND (LOWER([a].[czy]) = N‘abc‘)

 看来 let 在linq中还是有用的,再弄复杂一点呢?算了,还是越简单越好。容易出错。

 

 12、order by

 order by a.aaa,a.bbb,a.ccc descending

最简单了,不说了,注意的是:

先做Distinct再做OrderBy即可解決無法排序的問題
var result = (from a in dbContext.usergl_czy
select a.Times).Distinct().OrderBy(o=>o.aaa);

还有ThenBy,大家google一下吧

 

13、很重要的一点,根据不同的条件,进行延迟加载:

var ls_id = "abcd";

var ss = (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
  orderby a.czyid descending
  select new
  {
    a,
    b
  });

if(ls_id.RichErpIsNotNull())
{
    ss = (from a in ss
    where a.a.czyid == ls_id
    select a);
}

var lst = ss.ToList();

对应的sql为:

exec sp_executesql N‘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].[czyid] = @__ls_id_0‘,N‘@__ls_id_0 nvarchar(450)‘,@__ls_id_0=N‘abcd‘

只生成了一条sql。

 

最后,总结一个规律:

(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条件是没有限制的,用什么函数都行。

 

其他网上摘抄的,先记下来:


contact=====================
var q = (
from c in db.Customers
select c.Phone
).Concat(
from c in db.Customers
select c.Fax
).Concat(
from e in db.Employees
select e.HomePhone
);

语句描述:返回所有消费者和雇员的电话和传真。

2.复合形式:
var q = (
from c in db.Customers
select new
{
Name = c.CompanyName,
c.Phone
}
).Concat(
from e in db.Employees
select new
{
Name = e.FirstName + " " + e.LastName,
Phone = e.HomePhone
}

Union(合并)=====================================
说明:连接不同的集合,自动过滤相同项;延迟。即是将两个集合进行合并操作,过滤相同的项。
var q = (
from c in db.Customers
select c.Country
).Union(
from e in db.Employees
select e.Country
);

语句描述:查询顾客和职员所在的国家。

Intersect(相交)==============================
说明:取相交项;延迟。即是获取不同集合的相同项(交集)。即先遍历第一个集合,找出所有唯一的元素,然后遍历第二个集合,并将每个元素与前面找出的元素作对比,返回所有在两个集合内都出现的元素。
var q = (
from c in db.Customers
select c.Country
).Intersect(
from e in db.Employees
select e.Country
);

语句描述:查询顾客和职员同在的国家。

Except(与非)====================================
说明:排除相交项;延迟。即是从某集合中删除与另一个集合中相同的项。先遍历第一个集合,找出所有唯一的元素,然后再遍历第二个集合,返回第二个集合中所有未出现在前面所得元素集合中的元素。
var q = (
from c in db.Customers
select c.Country
).Except(
from e in db.Employees
select e.Country
);

语句描述:查询顾客和职员不同的国家。

Take ==================================

说明:获取集合的前n个元素;延迟。即只返回限定数量的结果集。
var q = (
from e in db.Employees
orderby e.HireDate
select e)
.Take(5);

语句描述:选择所雇用的前5个雇员。

Skip =====================================

说明:跳过集合的前n个元素;延迟。即我们跳过给定的数目返回后面的结果集。
var q = (
from p in db.Products
orderby p.UnitPrice descending
select p)
.Skip(10);

语句描述:选择10种最贵产品之外的所有产品。

TakeWhile ===============================================

说明:直到某一条件成立就停止获取;延迟。即用其条件去依次判断源序列中的元素,返回符合判断条件的元素,该判断操作将在返回false或源序列的末尾结束 。

SkipWhile ============================================

说明:直到某一条件成立就停止跳过;延迟。即用其条件去判断源序列中的元素并且跳过第一个符合判断条件的元素,一旦判断返回false,接下来将不再进行判断并返回剩下的所有元素。

Paging(分页)======================================

适用场景:结合Skip和Take就可实现对数据分页操作。

1.索引
var q = (
from c in db.Customers
orderby c.ContactName
select c)
.Skip(50)
.Take(10);

语句描述:使用Skip和Take运算符进行分页,跳过前50条记录,然后返回接下来10条记录,因此提供显示Products表第6页的数据。

2.按唯一键排序
var q = (
from p in db.Products
where p.ProductID > 50
orderby p.ProductID
select p)
.Take(10);

语句描述:使用Where子句和Take运算符进行分页,首先筛选得到仅50 (第5页最后一个ProductID)以上的ProductID,然后按ProductID排序,最后取前10个结果,因此提供Products表第6页


日期时间==================================================
EntityFunctions.DiffDays(rq.Date, a.rq) <= (a.tipdays ?? 0)

RichErp EfCore linq的正确写法

标签:last   排除   day   元素   ice   国家   def   intersect   莫名其妙   

原文地址:https://www.cnblogs.com/richerpxue/p/14311500.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!