Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.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
Asp.net mvc 在ASP.NETMVC中,将子对象添加到没有显式外键id字段且EF代码优先的父对象_Asp.net Mvc_Entity Framework_Ef Code First_Code First - Fatal编程技术网

Asp.net mvc 在ASP.NETMVC中,将子对象添加到没有显式外键id字段且EF代码优先的父对象

Asp.net mvc 在ASP.NETMVC中,将子对象添加到没有显式外键id字段且EF代码优先的父对象,asp.net-mvc,entity-framework,ef-code-first,code-first,Asp.net Mvc,Entity Framework,Ef Code First,Code First,我有两个模型类-Parent和Child,它们仅通过键入的导航属性链接 public class Parent { [Key] [Required] public int Id { get; set; } [Required] public string ParentName { get; set; } public virtual ICollection<Child> Children { get; set; } } publi

我有两个模型类-
Parent
Child
,它们仅通过键入的导航属性链接

public class Parent {
    [Key]
    [Required]
    public int Id { get; set; }

    [Required]
    public string ParentName { get; set; }

    public virtual ICollection<Child> Children { get; set; }
}

public class Child {
    [Key]
    [Required]
    public int Id { get; set; }

    [Required]
    public string ChildName { get; set; }

    [Required]
    public virtual Parent Parent { get; set; }
}
用户填写表单后,使用HTTP POST将数据发送到
Create
操作

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(Child child)
    {
        if (ModelState.IsValid)
        {
            //db.Parents.Attach(child.Parent); //Added later
            db.Children.Add(child);
            db.SaveChanges();
            return RedirectToAction("Index", new { parentId = child.Parent.Id });
        }
    }
这里我遇到了我的第一个问题。
child.Parent
不是空的,
child.Parent.Id
是正确的,但EF将其销毁,并在数据库中创建一个新的空父项(使用不同的键),并将该子项链接到它。我通过在添加
子对象之前将
子对象
db.Parents.Attach(child.Parent)
)附加到数据上下文,解决了这个问题

但后来我遇到了另一个问题。起初,我的模型类是错误的,没有
[Required]
属性,因此创建了可为空的数据库表列。我添加了属性,代码停止工作。代码不起作用,因为传递的
子项的
child.Parent.Name
null
,因此
ModelState.IsValid
false

如何解决将子对象添加到父对象的问题?我对以下解决方案感兴趣:

  • 首先使用EF代码和ASP.NETMVC
  • 不涉及从数据库中获取
    子.Parent
    ,只是为了让模型验证器满意
  • 不涉及向模型添加显式外键(
    ParentId

这可能吗?

我认为尝试将父对象附加到子对象有点倒退。通常,您会将子对象附加到父对象。正在创建一个新的父项,很可能是因为您的子模型中没有包含父项id为的输入元素。因此,当子项绑定到POST时,父项id可能为null。EF看到了这一点,认为您也想创建一个新的父级


此外,由于parentId是路由的一部分,因此不需要在视图模型中指定它,除非您对视图中的Html.BeginForm()执行特殊操作。也就是说,如果您只使用Html.BeginForm,它将使用发送给GET请求的相同URL值发布

创建方法

public ActionResult Create(int parentId) {
        var parent = db.Parents.Find(parentId);
        if (parent == null) {
            return HttpNotFound();
        }
        return View(new Child());
    }

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(int parentId, Child child)
{
    if (ModelState.IsValid)
    {
        //Probably not a bad idea to check again...just to be sure.
        //Especially since we are attaching a child to the parent object anyways.
        var parent = db.Parents.Find(parentId);
        if (parent == null) {
            return HttpNotFound();
        }
        parent.Childern.Add(child);
        db.SaveChanges();
        return RedirectToAction("Index", new { parentId = parentid });
    }
} 

我认为试图把父母和孩子联系在一起有点倒退。通常,您会将子对象附加到父对象。正在创建一个新的父项,很可能是因为您的子模型中没有包含父项id为的输入元素。因此,当子项绑定到POST时,父项id可能为null。EF看到了这一点,认为您也想创建一个新的父级


此外,由于parentId是路由的一部分,因此不需要在视图模型中指定它,除非您对视图中的Html.BeginForm()执行特殊操作。也就是说,如果您只使用Html.BeginForm,它将使用发送给GET请求的相同URL值发布

创建方法

public ActionResult Create(int parentId) {
        var parent = db.Parents.Find(parentId);
        if (parent == null) {
            return HttpNotFound();
        }
        return View(new Child());
    }

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(int parentId, Child child)
{
    if (ModelState.IsValid)
    {
        //Probably not a bad idea to check again...just to be sure.
        //Especially since we are attaching a child to the parent object anyways.
        var parent = db.Parents.Find(parentId);
        if (parent == null) {
            return HttpNotFound();
        }
        parent.Childern.Add(child);
        db.SaveChanges();
        return RedirectToAction("Index", new { parentId = parentid });
    }
} 
是指向您问题完整答案的链接。简而言之,当您处理断开连接的实体时,EF将不考虑已设置的实体ID,并将整个实体图标记为新的(例如添加的)

我个人不喜欢它,只是过度使用了SaveChanges(),尽管当您有一个带有int(或long)Id属性的EnityBase基类(我觉得非常方便)时,它的工作原理如下

是指向您问题完整答案的链接。简而言之,当您处理断开连接的实体时,EF将不考虑已设置的实体ID,并将整个实体图标记为新的(例如添加的)

我个人不喜欢它,只是过度使用了SaveChanges(),尽管当您有一个带有int(或long)Id属性的EnityBase基类(我觉得非常方便)时,它的工作原理如下


我认为这应该适用于Create方法:

public ActionResult Create([Bind(Exclude="Parent")]Child child)

我认为这应该适用于Create方法:

public ActionResult Create([Bind(Exclude="Parent")]Child child)
公共类菜单
{
//公共菜单()
//{
//    {
//this.Templates=newhashset();
//    }
//}
[关键]
public int MenuId{get;set;}
[列(“菜单选项”)]
[显示(Name=“菜单标题”)]
[长度(100)]
公共字符串菜单选项{get;set;}
[显示(名称=“父菜单”)]
public int?ParentMenuId{get;set;}
公共虚拟菜单父菜单{get;set;}
[显示(Name=“Is Group”)]
公共bool IsGroup{get;set;}
[显示(Name=“菜单顺序”)]
公共整数菜单项{get;set;}
[显示(Name=“可见性”)]
公共布尔可见性{get;set;}
[显示(Name=“可见性主菜单”)]
公共布尔可视性m{get;set;}
[列(“控制器”)]
[显示(Name=“Controller”)]
[长度(100)]
公共字符串控制器{get;set;}
[栏目(“行动”)]
[显示(Name=“操作”)]
[长度(150)]
公共字符串操作{get;set;}
[显示(Name=“Icon”)]
公共int?IconID{get;set;}
[外键(“IconID”)]
公共虚拟图标{get;set;}
公共虚拟ICollection模板{get;set;}
}
公共类菜单
{
//公共菜单()
//{
//    {
//this.Templates=newhashset();
//    }
//}
[关键]
public int MenuId{get;set;}
[列(“菜单选项”)]
[显示(Name=“菜单标题”)]
[长度(100)]
公共字符串菜单选项{get;set;}
[显示(名称=“父菜单”)]
public int?ParentMenuId{get;set;}
公共虚拟菜单父菜单{get;set;}
[显示(Name=“Is Group”)]
公共bool IsGroup{get;set;}
[显示(Name=“菜单顺序”)]
公共整数菜单项{get;set;}
[显示(Name=“可见性”)]
公共布尔可见性{get;set;}
[显示(Name=“可见性主菜单”)]
公共布尔可视性m{get;set;}
[列(“控制器”)]
  public class Menu
{
    //public Menu()
    //{
    //    {
    //        this.Templates = new HashSet<MenuTemplate>();
    //    }

    //}
    [Key]
    public int MenuId { get; set; }

    [Column("MenuCaption")]
    [Display(Name = "Menu Caption")]
    [StringLength(100)]
    public string MenuCaption { get; set; }

    [Display(Name = "Parent Menu")]
    public int? ParentMenuId { get; set; }
    public virtual Menu ParentMenu { get; set; }
    [Display(Name = "Is Group")]
    public bool IsGroup { get; set; }

    [Display(Name = "Menu Order")]
    public int MenuOrder { get; set; }

    [Display(Name = "Visibility")]
    public bool Visibility { get; set; }
    [Display(Name = "Visibility Main Menu")]
    public bool VisibilityMM { get; set; }
    [Column("Controller")]
    [Display(Name = "Controller")]
    [StringLength(100)]
    public string Controller { get; set; }
    [Column("Action")]
    [Display(Name = "Action")]
    [StringLength(150)]
    public string Action { get; set; }






    [Display(Name = "Icon")]
    public int? IconID { get; set; }
    [ForeignKey("IconID")]
    public virtual Icon Icon { get; set; }




    public virtual ICollection<MenuTemplate> Templates { get; set; }
}
var dataList = db.Menus.Include(X => X.Icon).ToList();
var ViewModellist = dataList.Join(dataList,
    a => a.ParentMenuId,
    b => b.MenuId,
    (_menu, _parent) => new MenuView
    {
        MenuId = _menu.MenuId,
        Action = _menu.Action,
        Controller = _menu.Controller,
        IsGroup = _menu.IsGroup,
        MenuCaption = _menu.MenuCaption,
        MenuOrder = _menu.MenuOrder,
        ParentMenuId = _menu.ParentMenuId,
        Visibility = _menu.Visibility,
        VisibilityMM = _menu.VisibilityMM,
        PMenuName = _parent.MenuCaption
    }).ToList();

if (PId == 0)
{
    var hierarchyList = ViewModellist.Where(x => x.ParentMenuId == null).OrderBy(x => x.MenuOrder).
   Select(x => new MenuView
   {
       MenuId = x.MenuId,
       Action = x.Action,
       Controller = x.Controller,
       IsGroup = x.IsGroup,
       MenuCaption = x.MenuCaption,
       MenuOrder = x.MenuOrder,
       ParentMenuId = x.ParentMenuId,
       PMenuName = x.PMenuName,
       Visibility = x.Visibility,
       VisibilityMM = x.VisibilityMM,
       ChildList = GetChildMenulist(x.MenuId, ViewModellist)

   }).FirstOrDefault();
    return View(hierarchyList);
}
else
{
    var hierarchyList = ViewModellist.Where(x => x.MenuId == PId).OrderBy(x => x.MenuOrder).
   Select(x => new MenuView
   {
       MenuId = x.MenuId,
       Action = x.Action,
       Controller = x.Controller,
       IsGroup = x.IsGroup,
       MenuCaption = x.MenuCaption,
       MenuOrder = x.MenuOrder,
       ParentMenuId = x.ParentMenuId,
       PMenuName = x.PMenuName,
       Visibility = x.Visibility,
       VisibilityMM = x.VisibilityMM,
       ChildList = GetChildMenulist(x.MenuId, ViewModellist)

   }).FirstOrDefault();
    return PartialView("_Index", hierarchyList);
}