首页 新闻 会员 周边 捐助

关于Linq to object和linq to entities混合使用的问题。

0
悬赏园豆:20 [已解决问题] 解决于 2016-12-27 23:29

如下代码,是一个列表和实体类左连接查询。

linq to object在前,查询时候会把c_material_sorg表中所有数据加载到内存中查询。

 

List<string> pns = new List<string>();
                pns.Add("06P4069");
                pns.Add("0A33908");
                pns.Add("0B66266");

                var tempPn = (from p in pns
                              join c in entity.c_material_sorg
                              on p equals c.Material into tempM
                              from oneM in tempM.DefaultIfEmpty()
                              select new
                              {
                                  pn = p,
                                  org = oneM == null ? "" : oneM.Sale_Org
                              }).ToList();

 

改成如下代码,linq to entities在前,查询时候就生成正常的sql语句查询,也不会全表数据都加载。

 var tempPn2 = (from c in entity.c_material_sorg
                               join p in pns
                               on c.Material equals p into tempM
                               from oneM in tempM.DefaultIfEmpty()
                               select new
                              {
                                  pn = oneM == null ? "" : oneM,
                                  org = c.Sale_Org
                              }).ToList();

问题:

如果三个表或object以上使用左连接查询,

1、如果要把linq to object的放前面用左连接查询,有什么方法或写法可以避免全表加载?

2、如果问题1没有方法,是否只能用拆分来实现objectentity多表联合查询。拆分是先联合entity实体类查询出数据,再把查询出来的object与现有的object联合查询。

大家有什么好的方法,麻烦指导下说说。

开山怪不怪的主页 开山怪不怪 | 小虾三级 | 园豆:544
提问于:2016-12-16 14:20
< >
分享
最佳答案
0

你都 ToList()了还存在避不避免?,你那个pns那样连接有什么意义吗

收获园豆:20
龙行天涯 | 小虾三级 |园豆:1794 | 2016-12-22 17:46

o   tolist那不是查询之后的事了么?pns这样连接,这边pns是别的地方传递过来的,要左连接超过三个表查询一些信息,这样写方便连接判断 。

现在能改的都改成用Contains语句了。

开山怪不怪 | 园豆:544 (小虾三级) | 2016-12-22 18:01

@黑峰: 有点不理解你这样做的目的,你的pns到底事拿来做什么的,有什么实际用处

龙行天涯 | 园豆:1794 (小虾三级) | 2016-12-22 18:56

@程序人生,永无止境: pns可以当做别的地方传递过来的主键。

就想左连接得出数据,这就是实际用处。类似这样:

 var pns = new List<string> {"11","22","33"};
                var tempPns = (from p in pns
                            join c in entity.categorydescription.Where(o => o.Language == language)
                           on p equals c.CategoryID into tempTable
                            from one in tempTable.DefaultIfEmpty()
                            join d1 in entity.category_solution_display.Where(o => o.Type == (int)CategorySolutionDisplayType.CategoryType && o.RegionCountry == country)
                            on p equals d1.Id into tempDisplay1
                            from oneDisplay1 in tempDisplay1.DefaultIfEmpty()
                            join d2 in entity.category_solution_display.Where(o => o.Type == (int)CategorySolutionDisplayType.CategoryType && o.RegionCountry == land)
                            on p equals d2.Id into tempDisplay2
                            from oneDisplay2 in tempDisplay2.DefaultIfEmpty()
                            join d3 in entity.category_solution_display.Where(o => o.Type == (int)CategorySolutionDisplayType.CategoryType && o.RegionCountry == "WW")
                            on p equals d3.Id into tempDisplay3
                            from oneDisplay3 in tempDisplay3.DefaultIfEmpty()
                            select new
                            {
                                id = p,
                                title = one == null ? p : one.Description,
                                display = oneDisplay1 != null ? oneDisplay1.Display : (oneDisplay2 != null ? oneDisplay2.Display : (oneDisplay3 != null ? oneDisplay3.Display : "N"))
                            }).ToList();
开山怪不怪 | 园豆:544 (小虾三级) | 2016-12-25 23:03

@黑峰: 既然是这样,你又担心全部加载,可以尝试一下改变你pns返回的数据类型,别的地方返回pns的时候不要返回list类型的数据,你直接返回一个IQueryable<T>类型的不就可以了。

        public IQueryable<string> rtQuerable()
        {
            var strList = new List<string>()
            {
                "a","b","c"
            };
            IQueryable<string> li = strList.AsQueryable();
            return li;
        }

这样最好,在pns方法的源头就不让数据加载到内存中。

如果你pns方法不能改,那就直接在你List<string> pns=new List(string){"11","22","33"}处吧pns转换成Iqueryable<T>类型,T是你要传入的类型。

      IQueryable<string> iq=pns.AsQueryable();

 

至于IQueryable与List的区别,你如果不了解的话可以先去了解一下。

龙行天涯 | 园豆:1794 (小虾三级) | 2016-12-26 09:03

@程序人生,永无止境: 

用IQueryable也是不行的。首先生成的语句就不是sql语句,估计还是会全表加载。其次这样写会报异常,如下图:

 

还是用Contains先查出来,再与原有pns对比做处理。Contains生成的语句就是sql,如下图:

开山怪不怪 | 园豆:544 (小虾三级) | 2016-12-27 16:05

代码:

  var pns = new List<string> { "0022A13", "0022A16", "0022A17" };
                var iQueryable = pns.AsQueryable();
                var temp1 = from i in iQueryable
                            join a in entity.accessory
                            on i equals a.PN
                            join c in entity.c_mtm_long_desc
                            on a.CategoryID equals c.MTMNUMBER into tempC
                            from oneC in tempC.DefaultIfEmpty()
                            select new
                            {
                                pn = i,
                                desc = oneC == null ? "" : oneC.MTMLONGDESC
                            };
                var temp2 = temp1.ToList();

                var temp3 =from a in entity.accessory.Where(o=>pns.Contains(o.PN))
                           join c in entity.c_mtm_long_desc
                          on a.CategoryID equals c.MTMNUMBER into tempC
                           from oneC in tempC.DefaultIfEmpty()
                           select new
                           {
                               pn = a.PN,
                               desc = oneC == null ? "" : oneC.MTMLONGDESC
                           };
                var temp4 = temp3.ToList();

 

开山怪不怪 | 园豆:544 (小虾三级) | 2016-12-27 16:07

@黑峰:
不行就分两步吧,我刚刚测试了一下确实不能两个用IQueryable类型去连接,linq本身不支持这样做。它要的是实体与实体之间。

龙行天涯 | 园豆:1794 (小虾三级) | 2016-12-27 18:59

@程序人生,永无止境: 嗯,表数据少的全表加载就加载吧,数据多的,多分两步处理。

开山怪不怪 | 园豆:544 (小虾三级) | 2016-12-27 23:28
其他回答(1)
0

数量少的话,查询逻辑复杂的可以object在前吧。别的 尽量修改吧

开山怪不怪 | 园豆:544 (小虾三级) | 2016-12-21 10:14
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册