Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从强类型视图提交多个模型表单时的模型绑定_C#_Asp.net Mvc_Html Helper_Model Binding - Fatal编程技术网

C# 从强类型视图提交多个模型表单时的模型绑定

C# 从强类型视图提交多个模型表单时的模型绑定,c#,asp.net-mvc,html-helper,model-binding,C#,Asp.net Mvc,Html Helper,Model Binding,我在绑定提交了多个模型的表单时遇到问题。我有一个投诉表,其中包括投诉信息以及一对多投诉人。我正试图提交表单,但绑定时出错。ModelState.IsValid始终返回false 如果我调试并查看ModelState错误,我会得到这样一个消息: “EntityCollection已初始化。在反序列化对象图期间,应仅调用InitializeRelatedCollection方法初始化新的EntityCollection” 此外,在调试时,我可以看到投诉模型确实从表单提交中填充了投诉人,因此该部分似乎

我在绑定提交了多个模型的表单时遇到问题。我有一个投诉表,其中包括投诉信息以及一对多投诉人。我正试图提交表单,但绑定时出错。ModelState.IsValid始终返回false

如果我调试并查看ModelState错误,我会得到这样一个消息: “EntityCollection已初始化。在反序列化对象图期间,应仅调用InitializeRelatedCollection方法初始化新的EntityCollection”

此外,在调试时,我可以看到投诉模型确实从表单提交中填充了投诉人,因此该部分似乎正在工作

我不确定使用默认的ModelBinder时我所做的是不是不可能的,或者我只是没有按照正确的方式进行。我似乎找不到任何具体的例子或文件。stackoverflow上也存在类似的问题,但它似乎不处理强类型视图

控制器代码:

    public ActionResult Edit(int id)
    {
        var complaint = (from c in _entities.ComplaintSet.Include("Complainants")
                     where c.Id == id
                     select c).FirstOrDefault();

        return View(complaint);
    }

    //
    // POST: /Home/Edit/5
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(Complaint complaint)
    {
        if (!ModelState.IsValid)
        {
            return View();
        }
        try
        {
            var originalComplaint = (from c in _entities.ComplaintSet.Include("Complainants")
                                     where c.Id == complaint.Id
                                     select c).FirstOrDefault();
            _entities.ApplyPropertyChanges(originalComplaint.EntityKey.EntitySetName, complaint);
            _entities.SaveChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }
视图代码(这是一个由创建/编辑视图调用的局部视图,这些视图也是带有投诉的强类型视图):


收到日期:
输入日期:
得出结论:
事件日期:

姓: GivenName1:
盲猜:

更改:

<%= Html.TextBox("Complainants[" + i + "].Surname", complainant.Surname)%>

与:


分别-在“投诉人[…”之前添加“投诉”

编辑

这不是一个正确的答案。请取消删除它,因为这可能会增加一些值,直到弹出正确的答案

EDIT2:

我可能错了,但对我来说,实体框架(或者-您使用它的方式)似乎有问题。我的意思是-asp.net mvc可以从请求中读取值,但无法初始化投诉人集合

上面写着:

InitializeRelatedCollection(TTargetEntity)方法初始化使用默认构造函数创建的现有EntityCollection(TEntity)。EntityCollection(TEntity)使用提供的关系和目标角色名称初始化

InitializeRelatedCollection(TTargetEntity)方法仅在反序列化过程中使用

更多信息:

例外情况:

  • 无效操作例外
条件:

  • 当提供的EntityCollection(TEntity)已初始化时
  • 当关系管理器已附加到ObjectContext时
  • 当关系管理器已包含具有此名称和目标角色的关系时
为什么InitializeRelatedCollection会被解雇两次。不幸的是,我不知道确切的原因。也许这项小小的调查会对其他人有所帮助——对EF更有经验。:)

EDIT3:
这不是针对这个特定问题的解决方案,更像是一种变通方法,一种处理mvc模型部分的正确方法

创建仅用于演示目的的viewmodel。也可以从纯POCO创建新的域模型(因为EF仅在下一版本中支持它们)。用于映射EFDataContextModelViewModel


这需要一些努力,但这是应该如何处理的。这种方法从您的模型中删除表示责任,清理您的域模型(从您的模型中删除EF内容)并且可以解决您的绑定问题。

我也有同样的问题!最终您会发现框架无法处理复杂的模型

我编写了一个小绑定组件,可以在post上初始化复杂的绑定


但基本上你要做的是Arnis L.告诉你的。

我通过以下操作解决了ModelBinding异常:

// Remove the error from ModelState which will have the same name as the collection.
ModelState.Remove("Complaints"/*EntityCollection*/); 
if (ModelState.IsValid) // Still catches other errors.
{
    entities.SaveChanges(); // Your ObjectContext
}
主要缺点是仍然会引发异常,这在运行时可能会很昂贵。解决的办法可能是围绕现有DefaultBinder创建一个包装器,防止它再次实例化EntityCollection,这已经由EF完成。然后将该集合绑定到表单值(FormCollection)

请记住,如果要绑定多个集合,则需要删除每个集合的错误

在我的实验中,该集合成功地保存了该集合所在图形中的根对象

希望这能帮助别人

public ActionResult Edit([Bind(Exclude = "Complainants")]Complaint model)
{
  TryUpdateModel(model.Complainants, "Complainants");
  if (!ModelState.IsValid)
  {
      // return the pre populated model
      return View(model);
  }

}
这对我有用!

我认为,当投诉对象被创建时,它的“投诉人”集合被初始化(因为实体框架自动逻辑),然后模型绑定器也尝试创建集合本身,这导致了错误。
但是,当我们尝试手动更新模型时,集合已经初始化,但不会要求model binder再次初始化它。

要在没有逐案解决方法的情况下使其正常工作,您需要创建自己的model binder并覆盖method SetProperty:

public class MyDefaultModelBinder : DefaultModelBinder
{
    protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
    { 
        ModelMetadata propertyMetadata = bindingContext.PropertyMetadata[propertyDescriptor.Name]; 
        propertyMetadata.Model = value;
        string modelStateKey = CreateSubPropertyName(bindingContext.ModelName, propertyMetadata.PropertyName);

        // Try to set a value into the property unless we know it will fail (read-only 
        // properties and null values with non-nullable types)
        if (!propertyDescriptor.IsReadOnly) { 
        try {
            if (value == null)
            {
            propertyDescriptor.SetValue(bindingContext.Model, value);
            }
            else
            {
            Type valueType = value.GetType();

            if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(EntityCollection<>))
            {
                IListSource ls = (IListSource)propertyDescriptor.GetValue(bindingContext.Model);
                IList list = ls.GetList();

                foreach (var item in (IEnumerable)value)
                {
                list.Add(item);
                }
            }
            else
            {
                propertyDescriptor.SetValue(bindingContext.Model, value);
            }
            }

        }
        catch (Exception ex) {
            // Only add if we're not already invalid
            if (bindingContext.ModelState.IsValidField(modelStateKey)) { 
            bindingContext.ModelState.AddModelError(modelStateKey, ex); 
            }
        } 
        }
    }
}

我已尝试此操作,但ModelState.IsValid仍返回false。ModelState键由符合项[0]填充。姓氏、投诉人[1]。姓氏等。导致其失败的原因是有一个名为投诉人的键。这就是导致我出错的原因“EntityCollection已经初始化。InitializeRelatedCollection方法只应在反序列化对象图期间调用以初始化新的EntityCollection”。使用EntityCollection时可能会出现问题。此链接:breifly介绍了它,但我对它知之甚少
public ActionResult Edit([Bind(Exclude = "Complainants")]Complaint model)
{
  TryUpdateModel(model.Complainants, "Complainants");
  if (!ModelState.IsValid)
  {
      // return the pre populated model
      return View(model);
  }

}
public class MyDefaultModelBinder : DefaultModelBinder
{
    protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
    { 
        ModelMetadata propertyMetadata = bindingContext.PropertyMetadata[propertyDescriptor.Name]; 
        propertyMetadata.Model = value;
        string modelStateKey = CreateSubPropertyName(bindingContext.ModelName, propertyMetadata.PropertyName);

        // Try to set a value into the property unless we know it will fail (read-only 
        // properties and null values with non-nullable types)
        if (!propertyDescriptor.IsReadOnly) { 
        try {
            if (value == null)
            {
            propertyDescriptor.SetValue(bindingContext.Model, value);
            }
            else
            {
            Type valueType = value.GetType();

            if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(EntityCollection<>))
            {
                IListSource ls = (IListSource)propertyDescriptor.GetValue(bindingContext.Model);
                IList list = ls.GetList();

                foreach (var item in (IEnumerable)value)
                {
                list.Add(item);
                }
            }
            else
            {
                propertyDescriptor.SetValue(bindingContext.Model, value);
            }
            }

        }
        catch (Exception ex) {
            // Only add if we're not already invalid
            if (bindingContext.ModelState.IsValidField(modelStateKey)) { 
            bindingContext.ModelState.AddModelError(modelStateKey, ex); 
            }
        } 
        }
    }
}
ModelBinders.Binders.DefaultBinder = new MyDefaultModelBinder();