I'm using Entity Framework 4 with MVC and need to ensure any referenced entities I want to use in my view have been loaded before the controller method returns, otherwise the view spits out the dreaded:
我正在使用带有MVC的Entity Framework 4,并且需要确保在我的视图中使用的任何引用实体在控制器方法返回之前已经加载,否则视图会吐出可怕的:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
ObjectContext实例已被释放,不能再用于需要连接的操作。
When selecting straight from the context, I can just use the Include(string)
method to force them to be included in the generated SQL query:
直接从上下文中选择时,我可以使用Include(string)方法强制它们包含在生成的SQL查询中:
var sellers = context.Sellers.Include("Recommendations.User").ToList();
However, if I have (for example) a helper method that accepts an entity and needs all items to be loaded, there's no Include
method available.
但是,如果我(例如)一个接受实体并需要加载所有项的辅助方法,则没有可用的Include方法。
void Test(Seller seller)
{
// ensure all recommendations and their users are loaded
}
The brute force approach is to loop through them:
蛮力方法是循环它们:
foreach (var recommendation in seller.Recommendations)
recommendation.User.ToString(); // just force a load
If I have 100 recommendations, this will create 101 SQL queries behind-the-scenes. Ideally I want a method/approach that loads all Recommendation
AND User
objects with only a single trip to SQL.
如果我有100条建议,这将在幕后创建101个SQL查询。理想情况下,我想要一种方法/方法,只需一次SQL访问即可加载所有建议和用户对象。
Show me the money.
给我看看钱款。
EDIT I'm not really interested in discussing whether this is a good or bad architecture. I've simplified my scenario for the sake of the question. Can you do what I'm asking with the EF API?
编辑我真的不想讨论这是一个好的或坏的架构。为了这个问题,我简化了我的方案。你能用EF API做我想问的吗?
EDIT 2
Ladislav's edit offered hope of a new approach, but it seems I'm not quite there.
拉迪斯拉夫的编辑提供了一种新方法的希望,但似乎我不是那里。
I can achieve what I want via this:
我可以通过这个实现我想要的:
context.Sellers.Include("Recommendations.User").Single(s => s.Id == seller.Id);
This approach doesn't work using LoadProperty
...
这种方法使用LoadProperty不起作用...
context.LoadProperty(seller, "Recommendations.User");
...as it fails with the error...
......因为错误而失败了......
The specified navigation property Recommendations.User could not be found.
找不到指定的导航属性Recommendations.User。
Neither of these approaches work if you don't have a reference to the context.
如果您没有对上下文的引用,这些方法都不起作用。
4 个解决方案
#1
5
This is an old question, but in EF6 you can accomplish loading dependent objects on an entity like this:
这是一个老问题,但在EF6中,您可以在实体上完成加载依赖对象,如下所示:
context.Entry(seller).Collection(s => s.Recommendations).Query().Include(r => r.User)).Load();
That would load all Recommendations
and their related Users
for the given seller
这将为给定的卖家加载所有建议书及其相关用户
#2
3
I think this is a job for your repository which should in your case expose methods like GetFullSeller (all properties loaded by Include) and GetSeller (only base entity).
我认为这是您的存储库的工作,在您的情况下应该公开GetFullSeller(由Include加载的所有属性)和GetSeller(仅基础实体)等方法。
Edit:
There are several ways how to load navigation properties in EF v4.
有几种方法可以在EF v4中加载导航属性。
- Eager loading (using Include)
- Lazy loading
- Explicit loading by ObjectContext.LoadProperty (doesn't work for POCO)
渴望加载(使用Include)
由ObjectContext.LoadProperty显式加载(对POCO不起作用)
There is no automatic loading.
没有自动加载。
#3
2
I'm in the same situation. I think that with EF is very easy to fall in a 101 query problem.
我处于同样的境地。我认为使用EF很容易陷入101查询问题。
A solution can be to create a partial class of your Seller class (generated by EF) and implement a GetSubclassNameQ that return a IQueryable, and a GetSubclassNameQFull that return a IQueryable with eager loading.
解决方案可以是创建Seller类的部分类(由EF生成)并实现返回IQueryable的GetSubclassNameQ,以及返回具有预先加载的IQueryable的GetSubclassNameQFull。
public partial class Seller{
public IQueryable<Recommendation> GetRecommendationsQ(EntityContainer entitycontainer) {
return entitycontainer.Recommendations;
}
public IQueryable<Recommendation> GetRecommendationsQFull(EntityContainer entitycontainer) {
return this.GetRecommendationsQ(entitycontainer).Include("Recommendations.User");
}
public IQueryable<Recommendation> GetRecommendationsQ() {
return GetRecommendationsQ(new EntityContainer());
}
public IQueryable<Recommendation> GetRecommendationsQFull() {
return this.GetRecommendationsQ().Include("Recommendations.User");
}
}
#4
0
Rather than passing your actual domain objects (EntityObject
s) to the view, you may want to use your controller to map them into a Model object that better represents what your view should actually be displaying. This will reduce the amount of logic required in your View, and have the pleasant side-effect of avoiding passing EntityObjects around after their context has expired.
您可能希望使用控制器将它们映射到更好地表示视图实际显示内容的Model对象,而不是将实际的域对象(EntityObjects)传递给视图。这将减少View中所需的逻辑量,并且具有避免在上下文过期后传递EntityObjects的令人愉快的副作用。
Edit based on your edit:
根据您的修改进行修改:
No, the API doesn't have a way to take a single Entity Object and make every other Entity Object of its type which was loaded at the same time it was be lazy-populated with a particular property in one fell swoop. You are better off pulling all of the items out in the first place using the Include
mention like you show in your question.
不,API没有办法获取单个实体对象并使其所有类型的其他实体对象在同时被一个特定属性延迟填充的同时被加载。最好先使用您在问题中显示的Include提及,将所有项目拉出来。
#1
5
This is an old question, but in EF6 you can accomplish loading dependent objects on an entity like this:
这是一个老问题,但在EF6中,您可以在实体上完成加载依赖对象,如下所示:
context.Entry(seller).Collection(s => s.Recommendations).Query().Include(r => r.User)).Load();
That would load all Recommendations
and their related Users
for the given seller
这将为给定的卖家加载所有建议书及其相关用户
#2
3
I think this is a job for your repository which should in your case expose methods like GetFullSeller (all properties loaded by Include) and GetSeller (only base entity).
我认为这是您的存储库的工作,在您的情况下应该公开GetFullSeller(由Include加载的所有属性)和GetSeller(仅基础实体)等方法。
Edit:
There are several ways how to load navigation properties in EF v4.
有几种方法可以在EF v4中加载导航属性。
- Eager loading (using Include)
- Lazy loading
- Explicit loading by ObjectContext.LoadProperty (doesn't work for POCO)
渴望加载(使用Include)
由ObjectContext.LoadProperty显式加载(对POCO不起作用)
There is no automatic loading.
没有自动加载。
#3
2
I'm in the same situation. I think that with EF is very easy to fall in a 101 query problem.
我处于同样的境地。我认为使用EF很容易陷入101查询问题。
A solution can be to create a partial class of your Seller class (generated by EF) and implement a GetSubclassNameQ that return a IQueryable, and a GetSubclassNameQFull that return a IQueryable with eager loading.
解决方案可以是创建Seller类的部分类(由EF生成)并实现返回IQueryable的GetSubclassNameQ,以及返回具有预先加载的IQueryable的GetSubclassNameQFull。
public partial class Seller{
public IQueryable<Recommendation> GetRecommendationsQ(EntityContainer entitycontainer) {
return entitycontainer.Recommendations;
}
public IQueryable<Recommendation> GetRecommendationsQFull(EntityContainer entitycontainer) {
return this.GetRecommendationsQ(entitycontainer).Include("Recommendations.User");
}
public IQueryable<Recommendation> GetRecommendationsQ() {
return GetRecommendationsQ(new EntityContainer());
}
public IQueryable<Recommendation> GetRecommendationsQFull() {
return this.GetRecommendationsQ().Include("Recommendations.User");
}
}
#4
0
Rather than passing your actual domain objects (EntityObject
s) to the view, you may want to use your controller to map them into a Model object that better represents what your view should actually be displaying. This will reduce the amount of logic required in your View, and have the pleasant side-effect of avoiding passing EntityObjects around after their context has expired.
您可能希望使用控制器将它们映射到更好地表示视图实际显示内容的Model对象,而不是将实际的域对象(EntityObjects)传递给视图。这将减少View中所需的逻辑量,并且具有避免在上下文过期后传递EntityObjects的令人愉快的副作用。
Edit based on your edit:
根据您的修改进行修改:
No, the API doesn't have a way to take a single Entity Object and make every other Entity Object of its type which was loaded at the same time it was be lazy-populated with a particular property in one fell swoop. You are better off pulling all of the items out in the first place using the Include
mention like you show in your question.
不,API没有办法获取单个实体对象并使其所有类型的其他实体对象在同时被一个特定属性延迟填充的同时被加载。最好先使用您在问题中显示的Include提及,将所有项目拉出来。