在Asp.net MVC视图延迟执行一个非常糟糕的事情? [英] Is Deferred Execution in Asp.net MVC View a very bad thing?
问题描述
让我们说我有这是通过实体框架得到以下模型:
Let's say i have the following model which is obtained via Entity Framework:
public class User{
public string Name {get;set;}
public int Id {get;set;}
}
获取一切从用户表中的用户:
Get all the users from the user table:
IEnumerable<User> users = from u in myDbContext.Users
select u;
瑞德在View(@model IEnumerable的)用户:
Reder the users in the View (@model IEnumerable):
@foreach(var item in Model)
{
<tr>@item.Id</tr>
<tr>@item.Name</tr>
}
我的新上司告诉我,做这种方式不符合MVC和性能会非常糟糕。我应该做的是materalize所有用户在控制器.ToList()。我不知道什么是更好的,因为无论哪种方式,用户必须物化和我没有看到任何性能损失。
My new boss is telling me that doing it this way is not MVC conform and the performance will be very bad. What i should do is to materalize all USERS in the Controller with .ToList(). I am not sure what is better, because either way the users have to be materialized and i dont see any performance losses.
推荐答案
延迟执行手段,LINQ前pression背后实际的SQL查询将不会被直到你开始访问的用户收集的项目执行(当您遍历那些在的foreach
循环)。这意味着,将有一个SELECT查询执行的,如果你试图访问一个导航性能(它是一个独特的记录)上的用户实体
Deferred execution means, your actual SQL query behind the LINQ expression won't be executed until you start accessing the items in the users collection (when you iterate those in the foreach
loop). That means, There will be a SELECT query executed if you are trying to access a navigational property (and it is a unique record) on the User entity
如果你只有一个用户表(就像你在你的问题已经呈现)没有任何外键/ vanigational性能,有了上面code你有,EF将只执行一个查询,从获取数据的用户表。但通常情况下这是不是这样的,你可能有外键有很多来自用户表不同的表。在这种情况下,实体框架做的事情不同。
If you only have a single user table (like what you have showed in your question) without any foreign keys/vanigational properties, With the above code you have, EF will execute only one query to get data from your User table. But typically this is not the case, You might have foreign keys to a lot of different tables from the User table. In that case Entity framework does thing differently.
让我们看一个例子。
假设我们有一个第二个表,用户类型有4列,编号
,名称
, code
和 IsAdmin
和您的用户表有一个称为第三列 UserTypeId
其中有一个外键到这个新的用户类型
表。每个用户记录与用户类型
记录相关联。
Assume that we have a second table, UserType which has 4 columns, Id
, Name
,Code
and IsAdmin
and your User table has a third column called UserTypeId
which has a foreign key to this new UserType
table. Every user record is associated with a UserType
record.
现在要显示所有与用户类型名称的用户。让我们来看看不同的做法。
Now you want to display all the Users with the UserType name. Let's see different approaches.
您将执行此code让所有的用户
You will execute this code to get all the users
var users = dbContext.Users;
和用户传递给剃刀视图,您将通过收集迭代。
And pass the users to the razor view where you will iterate through the collection.
@model IEnumerable<YourEntityNameSpace.User>
@foreach (var user in Model)
{
<div>
@user.Name - @user.UserType.Name
</div>
}
当我们执行这个页面,实体框架是要对用户表运行1选择查询到随着 UserTypeId
当在foreach块就是让用户记录正在执行,它要查询用户类型
表中的每个唯一 UserTypeId
从原来的结果集(用户
)。你可以看到这一点,如果你运行一个SQL事件探查器。
When we execute this page, Entity framework is going to run 1 select query on the User table to get the user records along with the UserTypeId
and when the foreach block is being executed, it is going to query the UserType
table for each unique UserTypeId
from the original result set(users
). You can see this if you run a SQL profiler.
您可以看到,EF正在通过 UserTypeId
(2我的图片)。我有3个不同的UserTypeId的用户表被使用,所以查询的用户等级和积分表3次,每个 UserTypeId
。
You can see that EF is passing UserTypeId
(2 in my picture). I had 3 different UserTypeId's being used in the User table, so it queried the UserType table 3 times, one for each UserTypeId
.
执行的SQL查询的数量:4 (1 user表+ 3用户等级和积分表)
Number of SQL queries executed : 4 (1 for user table + 3 for UserType table)
的我在用户类型表有3个不同的记录,我用所有这些在我的用户表格。的
I had 3 different records in the UserType table and i used all those in my User Table.
包含关键字是用来实现预先加载。预先加载就是一种类型实体的查询还加载相关实体作为查询的一部分的过程。
Include keyword is used to achieve eager loading. Eager loading is the process where a query for one type of entity also loads related entities as part of the query.
var users = dbContext.Users.Include(s=>s.UserType);
在这里,你告诉实体框架从 用户类型的表 用户的表一起查询。实体框架将产生一个INNER JOIN两个表之间的SQL查询并执行它。
Here you are telling Entity framework to query from UserType table along with User table. Entity framework will produce an INNER JOIN sql query between both the tables and execute it.
您可以看到,它查询的所有列在的用户类型的表)
You can see that, It queried all the columns of the UserType table)
执行的SQL查询数:1
通常情况下,这是不使用在其他层实体框架生成这么多的实体类是一个好主意。这使得你的code紧密耦合。
我建议只查询数据(列),这是需要的,并映射到POCO类(一个简单的DTO)和使用,在你的看法/其他层。你可以保持共同的项目,这些DTO类可以在其他项目(数据访问的项目和UI项目)
Usually, It is not a good idea to use the entity classes generated by Entity framework in other layers so much. That makes your code tightly coupled. I would suggest querying only data(columns) which is needed and map that to a POCO class (A simple DTO) and use that in your views /other layers. You may keep these DTO classes in common project which can be referred in other projects (Your Data Access project and UI project)
public class UserDto
{
public int Id {get;set;}
public string Name {get;set;}
public UserTypeDto UserType { set; get; }
}
public class UserTypeDto
{
public int Id { set; get; }
public string Name { set; get; }
}
我们的观点将被绑定到 UserDto
的集合insted的用户的实体
Our view will be bound to a collection of UserDto
insted of the User entity
@model IEnumerable<YourCommonNamespace.User>
@foreach (var user in Model)
{
<div> @user.Name - @user.UserType.Name </div>
}
现在从你的数据访问层,你将返回 UserDto
的集合,而不是用户
实体通过实体框架创建。
And now from your Data access layer, you will be returning a collection of UserDto
instead of the User
entity created by Entity framework.
var users = dbContext.Users.Select(s => new UserDto
{
Id = s.Id,
Name = s.Name,
UserType = new UserTypeDto
{
Id = s.UserType.Id,
Name = s.UserType.Name
}
});
在这里,你可以看到,我们使用选择
子句告诉EF哪些列,我们真正需要的。 EF将执行 INNER JOIN 的,但只有那些列,我们指定
Here, You can see that We are using the Select
clause to tell EF which columns we really need. EF will execute an INNER JOIN, but with only those columns, we specified
执行的SQL查询数:1
这种方法的好处是,如果你想从实体框架的数据访问实现切换到其他一些technologoy(纯ADO.NET/ NHibernate的),为你自己的原因,你将只更新GetUsers方法,所有其他层(剃刀意见/其他业务层code等),因为它们不使用由实体框架创建实体不需要更新。
The benefit of this approach is, If you ever want to switch your data access implementation from Entity framework to some other technologoy (Pure ADO.NET/ NHibernate) for your own reasons, You will be only updating your GetUsers method, All other layers (your Razor views/ Other Business layer code etc..) don't need an update because they are not using the entities created by entity framework.
如果你做了了ToList()
,EF执行SQL马上并返回结果。但是相反,如果你不这样做,因为延迟执行的,这是要执行SQL语句(S),当它真正需要的数据(例如:您呈现在循环中您的视图中的某些属性值)。
If you do a ToList()
, EF executes the SQL right away and return the result. But instead if you are not doing that, because of deferred execution, It is going to execute the SQL statement(s) when it actually needs the data (ex : You render some property value in your view inside the loop).
这篇关于在Asp.net MVC视图延迟执行一个非常糟糕的事情?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!