我想在ASP.NET MVC Web应用程序中创建一个名为Movie_Type
的新模型对象。如果我将此类的导航属性定义为以下List
,ICollection
或IQueryable
,会有什么不同?
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; }
}
OR
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; }
}
OR
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; }
}
修改: -
@Tomas Petricek。
感谢您的回复。在我的情况下,我使用数据库第一种方法,然后我使用DbContext
模板来映射我的表,自动为所有导航属性创建ICollection
,所以我的问题是: -
1.这是否意味着它并不总是使用Icollection的最佳选择。我应该更改自动生成的类以最适合我的情况。
2.其次,我可以设法通过定义.include(例如
var courses = db.Courses.Include(c => c.Department);
无论我使用什么来定义导航属性。所以我无法理解你的观点。
3.我没有找到任何使用IQuerable
定义导航属性的示例或教程,那么可能是什么原因?
BR
答案 0 :(得分: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
或者它将由延迟加载加载(如果导航属性为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);
}
}
最后一个选项是显式加载,这与我的意图最接近:
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);
}
}
答案 1 :(得分:8)
有两种可能的方式来看待事物:
结果是否作为对象实例的一部分存储在内存中?
如果选择ICollection
,结果将存储在内存中 - 如果数据集非常大或者您并不总是需要获取数据,这可能不是一个好主意。另一方面,当您将数据存储在内存中时,您将能够从程序中修改数据集。
您可以优化发送到SQL服务器的查询吗?
这意味着您可以在返回的属性上使用LINQ,并且其他LINQ运算符将转换为SQL - 如果您不选择此选项,则额外的LINQ处理将在内存中运行。
如果要将数据存储在内存中,则可以使用ICollection
。如果您希望能够优化查询,则需要使用IQueryable
。这是一个摘要表:
| | Refine query | Don't change query |
|-----------------|--------------|--------------------|
| In-memory | N/A | ICollection |
| Lazy execution | IQueryable | IEnumerable |
答案 2 :(得分:0)
更多的标准是IEnumerable,因为它是最不常见的分母。
如果您想为调用者提供额外的查询功能而无需10个存储库方法来处理不同的查询方案,则可以返回Iqueryable。
缺点是无数可能'count()'缓慢但如果对象实现了ICollection,则首先检查此接口是否有该值,而不必枚举所有项目。
还要注意,如果将iqueryable返回给不受信任的调用者,他们可以对iqueryable执行一些转换和方法调用,并获取对上下文,连接,连接字符串,运行查询等的访问权。
另请注意,nhibernate例如有一个查询对象,您可以将其传递给存储库以指定选项。使用实体框架,您需要返回IQueryable以增强查询条件
答案 3 :(得分:0)
如果您使用虚拟导航属性,实体框架实际为您创建的集合实现ICollection,但不实现IQueryable,因此您不能将IQueryable用于导航属性,如Slauma所说。
您可以自由地将属性定义为IEnumerable,因为ICollection扩展了IEnumerable,但是如果您这样做,那么您将失去向这些导航属性添加新子项的能力。