Linq to Entities 蛋疼锦集 第一期
【开发环境】

从表:C表


C表数据

返回数据(主表同时带出对应从表 分页后的数据,如图为每页5条数据)
[不知道读者注意到没有,该返回数据中,没有分页栏,
因为,分页跳转等不是本文重点,为减轻DEMO,
说明问题,仅在后台进行分页,前台返回对应结果即可]

【Just Code It】
1、Entity
public class M
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long Id { get; set; }
public string Keywords { get; set; }
[ForeignKey("Id")]
public virtual ICollection<C> c { get; set; }
}
[Table("c")]
public class C
{
[Key]
[Column(Order = 1)]
public long Id { get; set; }
[Key]
[Column(Order = 2)]
public string code { get; set; }
}
2、Model
public class resultModel
{
public long id { get; set; }
public string keywords { get; set; }
public IEnumerable<string> codes { get; set; }
}
3、Controller
private XLContext db = new XLContext();
public ViewResult Index(int pageIndex=1,int pageSize=5)
{
var result = db.M
.Select(p =>new resultModel{
id = p.Id,
keywords = p.Keywords,
codes = p.c.Select(c => c.code)
})
.OrderBy(p => p.id)
.Skip((pageIndex-1)*pageSize)
.Take(pageSize)
.ToList();
return View(result);
}
4、View页面就不给出来了,不是重点。问题来了。看图:

【问题分析】
仅仅根据报错信息,空对象,很难看出哪里出的问题,当然有经验的人肯定一眼就看出来问题的关键。
经过简单排除,我将问题范围缩小到Skip、Take、ToList
继续排除,如下几种情况都可以通过:
var result =r2.Skip(5);
var result =r2.Skip(5).Take(5);
var result =r2.Take(5);
var result =r2.ToList();
如下几种情况不通过:
var result =r2.Skip(5).ToList();
var result =r2.Take(5).ToList();
var result =r2.Skip(5).Take(5).ToList();
也就是说,使用了Skip()和Take()方法之后,不可以ToList()。
这是为什么呢?
跑到MSDN上查了相关信息:支持的和不支持的方法 (LINQ to Entities)
资料显示,其实,LINQ to Entities肯定是支持skip和take的,不然怎么分页啊,傻!
突然联想到,难道是因为LINQ to Entities不支持复杂类型?
我这里确实用到了复杂类型:
public class resultModel
{
public long id { get; set; }
public string keywords { get; set; }
public IEnumerable<string> codes { get; set; }
}
Model里面包含了 IEnumerable<string>.于是将其替换成 :
public class resultModel
{
public long id { get; set; }
public string keywords { get; set; }
//public IEnumerable<string> codes { get; set; }
public int counts { get; set; }
}
在controller层也做如下修改:
var result = db.M
.Select(p =>new resultModel{
id = p.Id,
keywords = p.Keywords,
counts = p.c.Count
})
.OrderBy(p => p.id)
.Skip((pageIndex-1)*pageSize)
.Take(pageSize)
.ToList();
此时,顺利取出数据,并正确带出了counts数目。也就印证了,问题的关键:
LINQ to Entities不支持复杂类型
但是,我又该如何解决问题呢?我需要取出那样子的结构,怎么去实现呢?
如果可以实现拼接string的话, IEnumerable<string>可以用带分隔符的string来替代。
在MSDN上查了很多资料,LINQ to Entities也没有找到什么方法可以支持拼接string。
无奈,谷哥提示我,实在没办法就舍弃掉关联,使用Join语句。
所以,产生了以下解决办法:
先通过GroupJoin查询出符合条件的主表主键,进行排序后分页。再通过关联,取出从表数据。
这样,就避免了关联后分页。
代码如下:
public ViewResult Index(int pageIndex=1,int pageSize=5)
{
//取出符合条件的id,分页
var IdList = db.M.GroupJoin(db.C,
m => m.Id,
c => c.Id,
(m, c) => m.Id)
.OrderBy(p => p)
.Skip((pageIndex - 1) * pageSize)
.Take(pageSize)
.ToList();
//根据上面已经分好页的id,取出所有数据和关联数据
var result = db.M
.Where(p => IdList.Contains(p.Id))
.Select(q => new resultModel
{
id = q.Id,
keywords = q.Keywords,
codes = q.c.Select(c => c.code)
})
.ToList();
return View(result);
}
OK.
这样做确实解决了问题。得到了想要的结果。
但是,效率上真心打折扣了!希望有大牛给出更好的解决方案!还有各位的各种吐槽,非常欢迎!
下篇将分析和这个问题有点关系的第二个棘手的问题。慢慢等吧!

浙公网安备 33010602011771号