如下代码,是一个列表和实体类左连接查询。
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没有方法,是否只能用拆分来实现object和entity多表联合查询。拆分是先联合entity实体类查询出数据,再把查询出来的object与现有的object联合查询。
大家有什么好的方法,麻烦指导下说说。
你都 ToList()了还存在避不避免?,你那个pns那样连接有什么意义吗
o tolist那不是查询之后的事了么?pns这样连接,这边pns是别的地方传递过来的,要左连接超过三个表查询一些信息,这样写方便连接判断 。
现在能改的都改成用Contains语句了。
@黑峰: 有点不理解你这样做的目的,你的pns到底事拿来做什么的,有什么实际用处
@程序人生,永无止境: 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();
@黑峰: 既然是这样,你又担心全部加载,可以尝试一下改变你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的区别,你如果不了解的话可以先去了解一下。
@程序人生,永无止境:
用IQueryable也是不行的。首先生成的语句就不是sql语句,估计还是会全表加载。其次这样写会报异常,如下图:
还是用Contains先查出来,再与原有pns对比做处理。Contains生成的语句就是sql,如下图:
代码:
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();
@黑峰:
不行就分两步吧,我刚刚测试了一下确实不能两个用IQueryable类型去连接,linq本身不支持这样做。它要的是实体与实体之间。
@程序人生,永无止境: 嗯,表数据少的全表加载就加载吧,数据多的,多分两步处理。
数量少的话,查询逻辑复杂的可以object在前吧。别的 尽量修改吧