为什么我的模型会再次访问DB,以获取已经在单独的LINQ连接语句中加载的相关属性?
背景信息:
我最近在我的ASP.NET MVC3 Linq应用程序上运行了一些性能分析我得到了一些令人费解的结果,我希望能够解决。
这是db结构的简化版本。建立外键关系。
表格客户端:
ID|Client Name|Vertical ID|
___________________________
1 |Client1 |2 |
2 |Client2 |5 |
3 |Client3 | |
表格垂直
ID|Vertical Name|
_________________
2 |Life |
5 |Guilt |
当我显示客户端列表时,我正在显示客户端名称和垂直。我的控制器很简单:
public ActionResult Index()
{
...
var model = repository.GetAllClients();
return View(model);
}
让所有客户端在垂直表(以及其他几个)上运行连接。
public IEnumerable<client> GetAllClients()
{
OperationsMetricsDataContext db = new OperationsMetricsDataContext();
var clients = from c in db.clients
join v in db.verticals on c.vertical equals v into tmp1
from v in tmp1.DefaultIfEmpty()
join sm in db.cel_sm_staffs on c.sm_id equals sm.cel_sm_id into tmp2
from sm in tmp2.DefaultIfEmpty()
join cel in db.cel_sm_staffs on c.cel_id equals cel.cel_sm_id into tmp3
from cel in tmp3.DefaultIfEmpty()
select c;
return clients;
}
在我的视图中,然后我尝试在部分客户端类中使用此方法显示我已绑定的垂直名称
public string getVerticalName()
{
return this.vertical == null ? "N/A" : this.vertical.vertical_name;
}
问题:
@foreach (var item in Model) {
<tr>
<td>
@Html.Raw(item.client_name)
</td>
<td>
@Html.Raw(item.getVerticalName())
</td>
我发现的问题是,即使我在原始模型中指定了连接,(并且我已经能够验证在将模型传递给视图之前垂直属性已加载了值),每次我调用getVerticalName方法,Linq再次自动转到数据库加载垂直,以便我可以访问垂直名称。这是非常低效的,因为我最终为每个客户端分别进行了一次db调用,以获取它们的垂直信息。
我在这里缺少什么?难道LINQ不应该知道该属性已经被绑定而不是去数据库检索它,还是我需要指定一些东西来告诉LINQ我的信息已经存在于模型中?
答案 0 :(得分:2)
不确定它在MVC中的行为,但也许你的问题是延迟加载相关实体。 您可以使用LoadOptions强制加载Linq-2-sql。
尝试
OperationsMetricsDataContext db = new OperationsMetricsDataContext();
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Client>(c => c.Vertical);
db.LoadOptions = dlo;
答案 1 :(得分:0)
我的第一印象是,只有在您应该更改后才能执行查询:return clients;
到return clients.ToList();
正如您的代码所示,我相信它会返回IQueryable
简单地转换为IEnumerable
,并且根据设计,IQueryable将在其枚举时随时转到服务器。