请问EF codefirst为什么是用List<>而不是用IQueryable<>?

hercules135 2017-10-17 01:40:44
如题

比如一个 blog 有一个 post集合,我看到所有的文档都介绍用list<post>来实现

但是这样如何解决当一个blog有5000个post而我只要前10条?

今天突然被问这个问题,有点懵逼.以前用linq to sql都会用IQueryable<>来实现类似计数和分页的功能,而EF这部分是如何解决的呢?
...全文
483 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
masanaka 2017-10-18
  • 打赏
  • 举报
回复
EF是个关系型实体框架,你可以用IQueryable<Post>来构建数据库,这个没问题,但是无法用blog.Posts.Add来添加Post,因为这个时候Posts对于某个blog来说,只是个查询表达式,而非数据实体集合,这会违背EF的设计初衷吧?
hwyqy 2017-10-18
  • 打赏
  • 举报
回复
其实应该是IQueryable会延迟加载,用到时候才具体加载数据,所以可以根据上下文优化 比如 a.Where(..).Where(...).Where(...) 三个Where等具体需要数据时候,会优化为一条sql语句 如果是ToList(),表示需要数据了,会导致立即执行 比如a.Where(...).ToList().Where(...) ToList会导致第一个Where开始执行查询数据库,后面的Where就是内存里搜索了
正怒月神 版主 2017-10-18
  • 打赏
  • 举报
回复
引用 14 楼 masanaka 的回复:
[quote=引用 11 楼 hanjun0612 的回复:] 抱歉,前面我说错了。应该是 tolist或者 firstordefault之类的时候,才会查询数据库。 take不会。普遍情况来说 ,如果 var q=dbcontext.User.take(10)。这个是 iqueryable的。所以只是一个sql语句,并不会加在数据。 所以你的问题是,不会获取5000条数据的。而是直接从数据库 抓取10条出来 我将楼上的回复改一下,免得误导人
不好意思,上面有个回复乱掉了,我再写一遍。 你说的是dbcontext.User.take(10),这个没错。 但是你回答LZ说,"所以你的问题是,不会获取5000条数据的。而是直接从数据库  抓取10条出来",这个是有问题的。 LZ情况应该指的是blog.Posts.Take(N),不是dbContext.Posts.Take,他的疑问是一个 blog 有一个 post集合,为什么用list<post>而不是IQueryable。 如果是用blog.Posts.Take(N)来取的话,仍旧是先取出这个blog下的所有posts后,再从内存里take N条数据。 顺便,你是版主,能不能把上面乱掉的回复帮我删了呀? [/quote] 哦,楼主的这个意思倒是没注意,如果是关联项 Icollection<T>的话,那是会将当前项的所有关联取出来。不过也是当前项的所有关联外键
masanaka 2017-10-18
  • 打赏
  • 举报
回复
引用 11 楼 hanjun0612 的回复:
抱歉,前面我说错了。应该是 tolist或者 firstordefault之类的时候,才会查询数据库。 take不会。普遍情况来说 ,如果 var q=dbcontext.User.take(10)。这个是 iqueryable的。所以只是一个sql语句,并不会加在数据。 所以你的问题是,不会获取5000条数据的。而是直接从数据库 抓取10条出来 我将楼上的回复改一下,免得误导人
不好意思,上面有个回复乱掉了,我再写一遍。 你说的是dbcontext.User.take(10),这个没错。 但是你回答LZ说,"所以你的问题是,不会获取5000条数据的。而是直接从数据库  抓取10条出来",这个是有问题的。 LZ情况应该指的是blog.Posts.Take(N),不是dbContext.Posts.Take,他的疑问是一个 blog 有一个 post集合,为什么用list<post>而不是IQueryable。 如果是用blog.Posts.Take(N)来取的话,仍旧是先取出这个blog下的所有posts后,再从内存里take N条数据。 顺便,你是版主,能不能把上面乱掉的回复帮我删了呀?
正怒月神 版主 2017-10-17
  • 打赏
  • 举报
回复
引用 8 楼 hercules135 的回复:
谢谢版主再次回答问题,我的疑惑集中在第二点上, 就是当 public virtual ICollection<EL_ExhibitCharge> EL_ExhibitCharge { get; set; } 这个属性在实际使用的时候 比如 obj.EL_ExhibitCharge.take(10) 这样的情况下 如果 EL_ExhibitCharge 有5000条,那我这样写 是直接拿了5000条到内存中然后取10条 还是 EF处理过 只会去查询前10条?
抱歉,前面我说错了。应该是 tolist或者 firstordefault之类的时候,才会查询数据库。 take不会。普遍情况来说 ,如果 var q=dbcontext.User.take(10)。这个是 iqueryable的。所以只是一个sql语句,并不会加在数据。 所以你的问题是,不会获取5000条数据的。而是直接从数据库 抓取10条出来 我将楼上的回复改一下,免得误导人
圣殿骑士18 2017-10-17
  • 打赏
  • 举报
回复
引用 5 楼 hercules135 的回复:
比如 这篇帖子中 http://www.cnblogs.com/Gyoung/archive/2013/01/17/2863145.html

public class Destination
    {
        public int DestinationId { get; set; }
        public string Name { get; set; }
        public string Country { get; set; }
        public string Description { get; set; }
        public byte[] Photo { get; set; }
        public List<Lodging> Lodgings { get; set; }
    }

    public class Lodging
    {
        public int LodgingId { get; set; }
        public string Name { get; set; }
        public string Owner { get; set; }
        public bool IsResort { get; set; }
        public Destination Destination { get; set; }
    } 
Lodgings 这个属性为什么使用List?而不是 IQueryable
你要知道,这个类是个 模型 类,它代表的是数据,它在很多时间需要被序列化,被传输的,当然原则上就应该用List,IQueryable只是个查询表达式。 为什么这么设计?EF就是这么设计的。
正怒月神 版主 2017-10-17
  • 打赏
  • 举报
回复
引用 5 楼 hercules135 的回复:
比如 这篇帖子中 http://www.cnblogs.com/Gyoung/archive/2013/01/17/2863145.html


public class Destination
{
public int DestinationId { get; set; }
public string Name { get; set; }
public string Country { get; set; }
public string Description { get; set; }
public byte[] Photo { get; set; }
public List<Lodging> Lodgings { get; set; }
}

public class Lodging
{
public int LodgingId { get; set; }
public string Name { get; set; }
public string Owner { get; set; }
public bool IsResort { get; set; }
public Destination Destination { get; set; }
}


Lodgings 这个属性为什么使用List?而不是 IQueryable


我想你理解出现了误差。iqueryable<T>只是组装sql语句。不适合主外键关联的概念。
导航属性你可以使用 list或者 ICollection来达到主外键关联。
ef框架自动生成的代码,都是 public virtual ICollection XXXX xxxxx{get;set;}
virtual可以使得导航属性具有延迟加载的效果。
至于使用list还是ICollection那要看你是否需要list的这么多功能了。
正怒月神 版主 2017-10-17
  • 打赏
  • 举报
回复
引用 4 楼 hercules135 的回复:
我们的框架没有做处理,或者说 我们正在考虑要不要处理,所以想请教 EF是否已经处理过 我们是否要考虑这类问题?还是可以直接用LIst作为属性表示一对多关系?
1 我们的框架没有做处理,或者说 我们正在考虑要不要处理 这个问题的根本思考方向,我觉得是,你们必须避免所有数据加载到内存里。所以不能先返回一个 var q = dbcontext.Users.tolist()。然后在对这个q进行操作。这类代码,就会使内存爆炸。因此你们应该返回一个iqueryable或者是已经过滤了的IEnumerable,并且增加 where等等的expression来支持表达式树。 例如 public virtual IEnumerable<T> FindList(Expression<Func<T, bool>> whereLamdba) { var _list = dbEF.Set<T>().AsNoTracking().Where<T>(whereLamdba); return _list.ToList(); } 调用方法可能是: var q = biz.FindList( x =>( x.属性==值 ) ); 2 List表示一对多的关系,这个问题应该是指导航属性吧? 那只要通过 特性标签来设置主外键关系就可以了。 public virtual ICollection<EL_ExhibitCharge> EL_ExhibitCharge { get; set; }
hercules135 2017-10-17
  • 打赏
  • 举报
回复
引用 7 楼 hanjun0612 的回复:
[quote=引用 5 楼 hercules135 的回复:] 比如 这篇帖子中 http://www.cnblogs.com/Gyoung/archive/2013/01/17/2863145.html

public class Destination
    {
        public int DestinationId { get; set; }
        public string Name { get; set; }
        public string Country { get; set; }
        public string Description { get; set; }
        public byte[] Photo { get; set; }
        public List<Lodging> Lodgings { get; set; }
    }

    public class Lodging
    {
        public int LodgingId { get; set; }
        public string Name { get; set; }
        public string Owner { get; set; }
        public bool IsResort { get; set; }
        public Destination Destination { get; set; }
    } 
Lodgings 这个属性为什么使用List?而不是 IQueryable
我想你理解出现了误差。 导航属性你可以使用 list或者 ICollection来达到主外键关联。 ef框架自动生成的代码,都是 public virtual ICollection XXXX xxxxx{get;set;} virtual可以使得导航属性具有延迟加载的效果。 至于使用list还是ICollection那要看你是否需要list的这么多功能了。 [/quote] 收到 谢谢
hercules135 2017-10-17
  • 打赏
  • 举报
回复
引用 6 楼 hanjun0612 的回复:
[quote=引用 4 楼 hercules135 的回复:] 我们的框架没有做处理,或者说 我们正在考虑要不要处理,所以想请教 EF是否已经处理过 我们是否要考虑这类问题?还是可以直接用LIst作为属性表示一对多关系?
1 我们的框架没有做处理,或者说 我们正在考虑要不要处理 这个问题的根本思考方向,我觉得是,你们必须避免所有数据加载到内存里。所以不能先返回一个 var q = dbcontext.Users.tolist()。然后在对这个q进行操作。这类代码,就会使内存爆炸。因此你们应该返回一个iqueryable或者是已经过滤了的IEnumerable,并且增加 where等等的expression来支持表达式树。 例如 public virtual IEnumerable<T> FindList(Expression<Func<T, bool>> whereLamdba) { var _list = dbEF.Set<T>().AsNoTracking().Where<T>(whereLamdba); return _list.ToList(); } 调用方法可能是: var q = biz.FindList( x =>( x.属性==值 ) ); 2 List表示一对多的关系,这个问题应该是指导航属性吧? 那只要通过 特性标签来设置主外键关系就可以了。 public virtual ICollection<EL_ExhibitCharge> EL_ExhibitCharge { get; set; }[/quote] 谢谢版主再次回答问题,我的疑惑集中在第二点上, 就是当 public virtual ICollection<EL_ExhibitCharge> EL_ExhibitCharge { get; set; } 这个属性在实际使用的时候 比如 obj.EL_ExhibitCharge.take(10) 这样的情况下 如果 EL_ExhibitCharge 有5000条,那我这样写 是直接拿了5000条到内存中然后取10条 还是 EF处理过 只会去查询前10条?
正怒月神 版主 2017-10-17
  • 打赏
  • 举报
回复
至于为什么codefirst使用list。我是不知道。你们底层这么封装的吗?
还是说,其实他已经提供了分页方法。
只是最后返回是一个List?
可能是这样的 var q=dbcontext.Users.where(lambda).orderby(lambda).skip(xxx).take(xxx).ToList()?

那么在tolist()之前,他都是 一个IQueryable。
大多情况下 firstordefault ,tolist()之前,都不会查询数据库。
hercules135 2017-10-17
  • 打赏
  • 举报
回复
比如 这篇帖子中 http://www.cnblogs.com/Gyoung/archive/2013/01/17/2863145.html

public class Destination
    {
        public int DestinationId { get; set; }
        public string Name { get; set; }
        public string Country { get; set; }
        public string Description { get; set; }
        public byte[] Photo { get; set; }
        public List<Lodging> Lodgings { get; set; }
    }

    public class Lodging
    {
        public int LodgingId { get; set; }
        public string Name { get; set; }
        public string Owner { get; set; }
        public bool IsResort { get; set; }
        public Destination Destination { get; set; }
    } 
Lodgings 这个属性为什么使用List?而不是 IQueryable
hercules135 2017-10-17
  • 打赏
  • 举报
回复
引用 3 楼 hanjun0612 的回复:
至于为什么codefirst使用list。我是不知道。你们底层这么封装的吗? 还是说,其实他已经提供了分页方法。 只是最后返回是一个List? 可能是这样的 var q=dbcontext.Users.where(lambda).orderby(lambda).skip(xxx).take(xxx)? 那么在take之前,他都是 一个IQueryable。 大多情况下take, firstordefault ,tolist()之前,都不会查询数据库。
我们的框架没有做处理,或者说 我们正在考虑要不要处理,所以想请教 EF是否已经处理过 我们是否要考虑这类问题?还是可以直接用LIst作为属性表示一对多关系?
正怒月神 版主 2017-10-17
  • 打赏
  • 举报
回复
那你应该先明白IQueryable<>和IEnumerable<>的区别。 IQueryable不会查询数据库。只是生成一段sql语句。 IEnumerable会查询数据库,并且加载数据到本地缓存。 举个例子 var q=dbcontext.Users.where(x=>x.id=1) 这个出来是一个IQueryable,其实并没有查询数据库。 var q=dbcontext.Users.where(x=>x.id=1) .FirstOrDefault() 或者 .ToList() 这个出来就是一个IEnumerable http://blog.csdn.net/hanjun0612/article/details/50070081
圣殿骑士18 2017-10-17
  • 打赏
  • 举报
回复
并没有什么分别。你理解错了

62,046

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧