模型时的形式公布在控制器绑定 - 导航属性不会自动加载 [英] Model binding in the controller when form is posted - navigation properties are not loaded automatically

查看:160
本文介绍了模型时的形式公布在控制器绑定 - 导航属性不会自动加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用实体框架4.2版。有两个班在我小的测试应用程序:

I'm using the Entity Framework version 4.2. There are two classes in my small test app:

public class TestParent
{
    public int TestParentID { get; set; }
    public string Name { get; set; }
    public string Comment { get; set; }

    public virtual ICollection<TestChild> TestChildren { get; set; }
}

public class TestChild
{
    public int TestChildID { get; set; }
    public int TestParentID { get; set; }
    public string Name { get; set; }
    public string Comment { get; set; }

    public virtual TestParent TestParent { get; set; }
}

填充有数据对象从数据库效果很好。所以,我可以使用 testParent.TestChildren.OrderBy(TC =&GT; tc.Name)。在我的code。首先()名称

然后我建了一个标准的编辑形式为我testParents。该控制器是这样的:

Then I built a standard edit form for my testParents. The controller look like this:

public class TestController : Controller
{
    private EFDbTestParentRepository testParentRepository = new EFDbTestParentRepository();
    private EFDbTestChildRepository testChildRepository = new EFDbTestChildRepository();

    public ActionResult ListParents()
    {
        return View(testParentRepository.TestParents);
    }

    public ViewResult EditParent(int testParentID)
    {
        return View(testParentRepository.TestParents.First(tp => tp.TestParentID == testParentID));
    }

    [HttpPost]
    public ActionResult EditParent(TestParent testParent)
    {
        if (ModelState.IsValid)
        {
            testParentRepository.SaveTestParent(testParent);
            TempData["message"] = string.Format("Changes to test parents have been saved: {0} (ID = {1})",
                                                        testParent.Name,
                                                        testParent.TestParentID);
            return RedirectToAction("ListParents");
        }
        // something wrong with the data values
        return View(testParent);
    }
}

当窗体回发到服务器模型绑定似乎运作良好 - 即testParent看起来不错(ID,姓名和预期评语集)。然而,导航属性TestChildren保持在NULL。

When the form is posted back to the server the model binding appears to be working well - i.e. testParent looks okay (id, name and comment set as expected). However the navigation property TestChildren remains at NULL.

这我想是不是SOOO奇怪,因为该模型仅仅提取物的结合,因为他们是从浏览器发送的形式值,并将其推入TestParent类的对象。填充testParent.TestChildren然而需要立即往返于它是实体框架的责任数据库。和EF可能不会涉足绑定过程。

This I guess is not sooo surprising since the model binding merely extracts the form values as they were sent from the browser and pushes them into an object of the TestParent class. Populating testParent.TestChildren however requires an immediate roundtrip to the database which is the responsibility of the Entity Framework. And EF probably doesn't get involved in the binding process.

我期待但延迟加载踢的时候我叫 testParent.TestChildren.First()。相反,导致一个ArgumentNullException。

I was however expecting the lazy loading to kick in when I call testParent.TestChildren.First(). Instead that leads to an ArgumentNullException.

是否有必要在模型绑定,使实体框架会做懒加载后一种特殊的方式来标记一个对象?我怎样才能做到这一点?

Is it necessary to tag an object in a special way after model binding so that the Entity Framework will do lazy loading? How can I achieve this?

很显然,我可以手动检索与第二库中的孩子 testChildRepository 。但是,这(一)感觉不对和(b)导致问题,我的存储库设置方式(​​每次使用自己的DbContext - 这是我没有设法达成协议还带有一个问题)。

Obviously I could manually retrieve the children with the second repository testChildRepository. But that (a) doesn't feel right and (b) leads to problems with the way my repositories are set up (each using their own DBContext - which is an issue that I haven't managed to come to terms with yet).

推荐答案

为了偷懒加载为您的孩子收集两个条件必须满足:

In order to get lazy loading for your child collection two requirements must be fulfilled:


  • 的母公司必须连接到EF上下文

  • 您的母公司必须是一个懒加载代理

如果您通过上下文从数据库装载父实体两个要求得到满足(和你的导航属性是虚拟允许代理创建)。

Both requirements are met if you load the parent entity from the database through a context (and your navigation properties are virtual to allow proxy creation).

如果你不加载从数据库中的实体,而是通过使用适当的EF功能手动创建它,你可以达到同样的:

If you don't load the entity from the database but create it manually you can achieve the same by using the appropriate EF functions:

var parent = context.TestParents.Create();
parent.TestParentID = 1;
context.TestParents.Attach(parent);

使用创建,而不是这里是重要的,因为它创建所需的延迟加载代理。然后,您可以访问子收集和= 1将延迟加载ID为父母的孩子:

Using Create and not new is important here because it creates the required lazy loading proxy. You can then access the child collection and the children of parent with ID = 1 will be loaded lazily:

var children = parent.TestChildren; // no NullReferenceException

现在,默认的模型绑定器没有关于这些具体的EF功能线索,将简单地实例化母公司新,也不会附加到任何环境。这两个要求都没有满足和懒加载无法正常工作。

Now, the default modelbinder has no clue about those specific EF functions and will simply instantiate the parent with new and also doesn't attach it to any context. Both requirements are not fulfilled and lazy loading cannot work.

您可以编写自己的模型绑定来创建实例的Create()但是这可能是最糟糕的解决方案,它将使您的视图层非常EF依赖。

You could write your own model binder to create the instance with Create() but this is probably the worst solution as it would make your view layer very EF dependent.

如果你需要的模型后,子集合结合我会在这种情况下,通过明确加载加载:

If you need the child collection after model binding I would in this case load it via explicit loading:

// parent comes as parameter from POST action method
context.TestParents.Attach(parent);
context.Entry(parent).Collection(p => p.TestChildren).Load();

如果你的背景和EF隐藏在背后的资源库,你需要为这个新的存储库的方法,如:

If your context and EF is hidden behind a repository you will need a new repository method for this, like:

void LoadNavigationCollection<TElement>(T entity,
    Expression<Func<T, ICollection<TElement>>> navigationProperty) 
    where TElement : class
{
    _context.Set<T>().Attach(entity);
    _context.Entry(entity).Collection(navigationProperty).Load();
}

...其中 _context 是库的类成员。

但更好的办法,因为达林所说,是绑定的ViewModels,然后根据需要将它们映射到你的实体。然后,你就可以选择用来实例化实体的Create()

But the better way, as Darin mentioned, is to bind ViewModels and then map them to your entities as needed. Then you would have the option to instantiate the entities with Create().

这篇关于模型时的形式公布在控制器绑定 - 导航属性不会自动加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆