ASP.Net MVC 3, Complex Objects and Lazy Loading
First of all, I am new to ASP.Net MVC 3, and I am also using EF 4.1.
I have a complex object, something similar to let's say a Product object containing a Category object. So we have Product.CategoryId, Product.Category and some extra properties. I also have a form to create products with a dropdown list to select the category.
In my controller, after the product has been created, I need to have access to some property of the Category to perform some extra stuff. However, although Product.CategoryId is set, I cannot access Product.Category.SomeProperty because Product.Category is null. I expected Product.Category would be loaded automatically using some lazy loading, but it does not seem to be.
The code in my Controller looks like this:
[HttpPost]
public ActionResult Create(Product product)
{
if (ModelState.IsValid)
{
db.Products.Add(开发者_如何转开发product);
db.SaveChanges();
string someString = product.Category.SomeProperty;
...
Now, this does not work because product.Category is null. What do I need to add so that I can access SomeProperty?
Lazy loading will not work in this scenario because you are adding a new object. Lazy loading will work on "Proxy" entities created by EF context.
So what you can do here is explicitly load the navigational property.
db.Products.Add(product);
db.SaveChanges();
db.Entry(product).Reference(p => p.Category).Load();
string someString = product.Category.SomeProperty;
Lazy loading doesn't work in your case because the product
which is passed in into the controller action is not a proxy object but created as an ordinary Product
instance by the model binder.
What you expect would work if product
is created as a proxy:
var product = db.Products.Create();
product.CategoryId = 1;
db.Products.Add(product);
db.SaveChanges();
string someString = product.Category.SomeProperty;
// Category gets lazily loaded now
The Category
property on the Product
class must be virtual
of course to have lazy loading working at all.
It doesn't help you in your situation because the model binder doesn't create a proxy.
Solutions: Either explicite loading (see @Eranga's answer) or in case you really only need to inspect the SomeProperty
of the category fetch the value in a projection:
string someString = db.Entry(product).Reference(p => p.Category).Query()
.Select(c => c.SomeProperty).SingleOrDefault();
...or (because you have the key of the category)...
string someString = db.Categories.Where(c => c.Id == product.CategoryId)
.Select(c => c.SomeProperty).SingleOrDefault();
You may need to explicitly enable lazy loading in your entity framework object context, as described in the MSDN article How to: Use Lazy Loading to Load Related Objects
In the Entity Framework runtime, the default value of the LazyLoadingEnabled property in an instance of ObjectContext is false.
db.ContextOptions.LazyLoadingEnabled = true;
More detail is provided in the Loading Related Objects article, just look in the section labeled "Lazily Loading Entity Objects".
精彩评论