我正在使用围绕Entity Framework Code First和ASP.NET MVC 5构建的N层解决方案。
我的Artist Controller中有以下ActionResult。
public ActionResult Paintings(string urlfriendly)
{
var artist = _artistService.GetArtistByUrlFriendly(urlfriendly);
ArtistPaintingsVM vm = Mapper.Map<ArtistPaintingsVM>(artist);
return View(vm);
}
该服务最终到达这里:
public Artist GetArtistByUrlFriendly(string urlFriendly)
{
var artist = _context.Artists.FirstOrDefault(a => a.UrlFriendly == urlFriendly && a.Verified);
if (artist != null)
{
artist.Paintings = _context.Paintings.Where(p => p.ArtistId == artist.Id && p.Verified).ToList();
}
return artist;
}
当我逐步执行该代码时,将获得所需的结果。我得到了那位艺术家的两幅经过验证的画作。但是,当我在不调试的情况下运行应用程序时,即使没有验证其中一幅,我也会获得艺术家的所有三幅画!
我上面的代码应该只返回经过验证的绘画,并且它是在调试中进行的,而不是在正常运行模式下进行的。
这是数据种子代码:
public class DXIntializer : DropCreateDatabaseAlways<DXContext>
{
protected override void Seed(DXContext context)
{
try
{
var artists = new List<Artist>
{
new Artist { FName = "Salvador", LName = "Dali", ImgURL = "http://i62.tinypic.com/ss8txxn.jpg", UrlFriendly = "salvador-dali", Verified = true }
};
artists.ForEach(a => context.Artists.Add(a));
context.SaveChanges();
var paintings = new List<Painting>
{
new Painting { Title = "The Persistence of Memory", ImgUrl = "http://i62.tinypic.com/xx8tssn.jpg", ArtistId = 1, Verified = true },
new Painting { Title = "Swans Reflecting Elephants", ImgUrl = "http://i62.tinypic.com/aa9tssn.jpg", ArtistId = 1, Verified = true },
new Painting { Title = "Crucifiction", ImgUrl = "http://i62.tinypic.com/qq0tssn.jpg", ArtistId = 1, Verified = false }
};
paintings.ForEach(p => context.paintings.Add(p));
context.SaveChanges();
}
catch (DbEntityValidationException ex)
{
foreach (var validationErrors in ex.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
}
}
}
}
}
我究竟做错了什么?
最佳答案
如果Paintings
类的Artist
属性是虚拟的,例如
public virtual List<Painting> Paintings { get; set; }
使其变为非虚拟(turn off lazy loading),如下所示:
public List<Painting> Paintings { get; set; }
此修复程序可以使您的代码继续运行。如果它已经不是虚拟的,请提供这些实体的源代码以帮助我们理解问题。
说明+少量建议
使用实体框架构建的N层解决方案很可能涉及实体的序列化。在您的情况下,用于检索数据的服务(我想是wcf或Web api)将序列化Artist对象并将其传递给UI层。现在,lazy loading and serialization don't mix well.当序列化器访问
Paintings
属性时,由于延迟加载,最终它会加载所有属于该艺术家的绘画。在调试时,请尝试以下操作:完全不要检查艺术家对象上的\悬停,也不要将其从监视中移出,在return artist;
语句上设置断点。按下F5键,当执行在return语句处暂停时,探索艺术家对象,您应该会看到所有三幅画。在为值分配值之前,请确保没有NOTHING会触发对Paintings
属性的评估。最好这样声明导航属性:
public List<Painting> Paintings { get; private set; }
这将强制使用导航属性。即您可以在收藏夹中添加或删除商品,但是不能分配新的收藏夹。在默认构造函数中初始化此类属性非常重要,如下所示:public class Artist { public List Paintings { get; private set; } public Artist() { this.Paintings = new List(); } }
- When you turn off lazy loading, you must explicitly load related entities.
In your case, instead of directly assigning values to the Paintings
property, you should rather do the following:
db.Entry<Artist>(artist)
.Collection(a => a.Paintings)
.Query()
.Where(p => p.Verified)
.Load();
它将仅加载指定艺术家的经过验证的绘画(应禁用延迟加载)。