我正在使用围绕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();
        }
    }
  1. 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();


它将仅加载指定艺术家的经过验证的绘画(应禁用延迟加载)。

09-06 05:54