在Asp.net MVC视图延迟执行一个非常糟糕的事情? [英] Is Deferred Execution in Asp.net MVC View a very bad thing?

查看:104
本文介绍了在Asp.net MVC视图延迟执行一个非常糟糕的事情?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们说我有这是通过实体框架得到以下模型:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆