定义Navigation属性时列出vs IEnumerable vs IQueryable

joh*_* Gu 14 linq entity-framework asp.net-mvc-3

我想创建一个Movie_Type在我的ASP.NET MVC Web应用程序中命名的新模型对象.如果我将此类的导航属性定义为或者如下List,那将会有什么不同?ICollectionIQueryable

public partial class Movie_Type
{ 
    public int Id { get; set; }
    public string Name { get; set; } 
    public string Description { get; set; } 
    public List<Movie> Movies { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

要么

public partial class Movie_Type
{ 
    public int Id { get; set; }
    public string Name { get; set; } 
    public string Description { get; set; } 
    public IQueryable<Movie> Movies { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

要么

public partial class Movie_Type
{
    public int Id { get; set; }
    public string Name { get; set; } 
    public string Description { get; set; } 
    public ICollection<Movie> Movies { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

编辑: - @Tomas Petricek.感谢您的回复.在我的情况下,我使用数据库第一种方法,然后我使用DbContext模板来映射我的表,这是自动创建ICollection的所有导航属性,所以我的问题是: - 1.这是否意味着它并不总是最好的选择使用ICollection的.我应该更改自动生成的类以最适合我的情况.2.其次,我可以设法通过定义.include等来选择延迟或预先加载

var courses = db.Courses.Include(c => c.Department);
Run Code Online (Sandbox Code Playgroud)

无论我用什么来定义导航属性.所以我无法理解你的观点.3.我没有找到任何IQuerable用于定义导航属性的示例或教程,那么可能是什么原因?BR

Sla*_*uma 15

您不能使用类型的导航属性IQueryable<T>.您必须使用ICollection<T>或某些实现的集合类型ICollection<T>- 比如List<T>.(IQueryable<T>没有实施ICollection<T>.)

导航属性只是内存中的对象或对象集合,null或者集合是空的.

当您从数据库加载包含导航属性的父对象时,它永远不会从数据库加载.

您要么必须明确表示要将导航属性与急切加载的父项一起加载:

var movieTypes = context.Movie_Types.Include(m => m.Movies).ToList();
// no option to filter or sort the movies collection here.
// It will always load the full collection into memory
Run Code Online (Sandbox Code Playgroud)

或者它将通过延迟加载加载(如果您的导航属性是默认情况下启用virtual):

var movieTypes = context.Movie_Types.ToList();
foreach (var mt in movieTypes)
{
    // one new database query as soon as you access properties of mt.Movies
    foreach (var m in mt.Movies)
    {
        Console.WriteLine(m.Title);
    }
}
Run Code Online (Sandbox Code Playgroud)

最后一个选项是显式加载,我认为最接近你的意图:

var movieTypes = context.Movie_Types.ToList();
foreach (var mt in movieTypes)
{
    IQueryable<Movie> mq = context.Entry(mt).Collection(m => m.Movies).Query();
    // You can use this IQueryable now to apply more filters
    // to the collection or sorting, for example:
    mq.Where(m => m.Title.StartWith("A"))   // filter by title
      .OrderBy(m => m.PublishDate)          // sort by date
      .Take(10)                             // take only the first ten of result
      .Load();                              // populate now the nav. property
    // again this was a database query

    foreach (var m in mt.Movies)    // contains only the filtered movies now
    {
        Console.WriteLine(m.Title);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一种耻辱,因为这意味着你必须在整个地方传递上下文,只是为了进行有效的子查询而不是天真的导航. (2认同)

Tom*_*cek 8

有两种可能的方式来看待事物:

  1. 结果是作为对象实例的一部分存储在内存中的吗?
    如果您选择ICollection,结果将存储在内存中 - 如果数据集非常大或者您并不总是需要获取数据,这可能不是一个好主意.另一方面,当您将数据存储在内存中时,您将能够从程序中修改数据集.

  2. 您可以优化发送到SQL服务器的查询吗?
    这意味着您可以在返回的属性上使用LINQ,并且其他LINQ运算符将转换为SQL - 如果您不选择此选项,则额外的LINQ处理将在内存中运行.

如果要将数据存储在内存中,则可以使用ICollection.如果您希望能够优化查询,则需要使用IQueryable.这是一个摘要表:

|                 | Refine query | Don't change query |
|-----------------|--------------|--------------------|
|  In-memory      |    N/A       |    ICollection     |
|  Lazy execution | IQueryable   |    IEnumerable     |
Run Code Online (Sandbox Code Playgroud)

  • 您不能将`IQueryable <T>`用于导航属性. (4认同)
  • +1 - 令人惊讶的是一张图片(如果这就是你可以称之为你的图表)的价值是1000字.我只是把灯泡打开事件:) (2认同)