繁体   English   中英

ASP.NET MVC实体框架6导航属性未保存在Edit的SaveChanges()存储库模式中

[英]ASP.NET MVC Entity Framework 6 Navigation Property not saving on SaveChanges() Repository Pattern on Edit

我遇到一个奇怪的问题,导航属性不存在于页面更新中,而存在于创建中。 我在Entity Framework 6,ASP.NET MVC 5中使用了通用存储库模式。

这是基本代码:

我的情况:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext() : base("DefaultConnection") { }       
}

我的存储库实现:

public class EntityFrameworkRepository : IRepository, IDisposable
{
    private ApplicationDbContext _context;
    private readonly ConcurrentDictionary<Type, object> _dbSets =
        new ConcurrentDictionary<Type, object>();

    public EntityFrameworkRepository(ApplicationDbContext context)
    {
        _context = context;
    }

    public void Save<T>(T entity) where T : BaseModel
    {
        GetDbSet<T>().Add(entity);
        _context.SaveChanges();
    }

    public void Update<T> (T entity) where T: BaseModel
    {
        _context.Entry(entity).State = EntityState.Modified;
        _context.SaveChanges();
    }
}

在这里,“获取编辑”页面的基础使用AutoMapper在域模型和视图模型之间进行映射。

public ActionResult Edit(int menuId, int? id)
{
   MenuItem mi = _repository.Get<MenuItem>((int)id);
   Mapper.CreateMap<MenuItem, MenuItemViewModel>();
   MenuItemViewModel mivm = Mapper.Map<MenuItem, MenuItemViewModel>(mi);
///....///
}

这是行不通的方法。 如您所见,整个对象UseSiblingClaim正在通过id检索,并设置为MenuItem itemToSave。 我在调用_repository.Update()之前检查对象,并且属性正确。

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int menuId, [Bind(Include = "Id,Name,ControllerName,ActionName,Order,CustomUrl,Tooltip,IconClass,CanUseParentsClaim,DoesNotNeedClaim,UseSiblingClaim_Id")] MenuItemViewModel mivm)
{
    if (ModelState.IsValid)
    {
        mivm.Menu = _repository.Get<Menu>(menuId);

        if (mivm.UseSiblingClaim_Id != null)
        {
           mivm.UseSiblingClaim = _repository.Get<MenuItem>((int)mivm.UseSiblingClaim_Id);
        }

        MenuItem itemToSave = MapViewModelToModel(mivm, _repository);
        _repository.Update<MenuItem>(itemToSave);
        return RedirectToAction("Details", "Menu", new { Id = menuId });
     }
     return View(mivm);
 }

这是MenuItem类:

public class MenuItem : BaseModel
{
    public MenuItem()
    {
        Children = new HashSet<MenuItem>();
    }        

    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }        
    public virtual MenuItem ParentMenuItem { get; set; }
    public virtual Menu Menu { get; set; }        
    public string Name { get; set; }
    ///.....///
    public virtual MenuItem UseSiblingClaim { get; set; }
}

映射方法在此处:正在设置UseSiblingClaim。

private static MenuItem MapViewModelToModel(MenuItemViewModel mivm, IRepository _repository)
    {


        MenuItem itemToSave = new MenuItem()
        {
            UseSiblingClaim = mivm.UseSiblingClaim,
            Id = mivm.Id,
            ActionName = mivm.ActionName,
            CanUseParentsClaim = mivm.CanUseParentsClaim,
            ControllerName = mivm.ControllerName,
            CustomURL = mivm.CustomURL,
            DoesNotNeedClaim = mivm.DoesNotNeedClaim,
            IconClass = mivm.IconClass,
            Menu = mivm.Menu,
            Name = mivm.Name,
            Order = mivm.Order,
            ParentMenuItem = mivm.ParentMenuItem,
            Tooltip = mivm.Tooltip,                     
        };
        return itemToSave;
    }

这是视图模型:

public class MenuItemViewModel : BaseModel
    {
        public int Id { get; set; }
        public int ParentMenuItem_Id { get; set; }
        public MenuItem ParentMenuItem { get; set; }
        public int Menu_Id { get; set; }
        public Menu Menu { get; set; }
        public IEnumerable<SelectListItem> SiblingItems { get; set; }
        [DisplayName("Can Use Sibling's Claim")]
        public int? UseSiblingClaim_Id { get; set; }
        public MenuItem UseSiblingClaim { get; set; }
    }

视图部分(对于Create()和Update()来说是相同的:

<div class="form-group">
    @Html.LabelFor(model => model.UseSiblingClaim_Id, new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.DropDownListFor(x => x.UseSiblingClaim_Id, Model.SiblingItems, new { @class = "select2", @multiple = "multiple", @style = "width:100%" })
        @Html.ValidationMessageFor(model => model.UseSiblingClaim_Id)
    </div>
</div>

创建Model.SiblingItems并将其传递到视图中。

为什么不保留UseSiblingClaim导航属性? 它适用于创建菜单项,但不适用于更新吗? 使用通用存储库模式与我有关系吗? 请帮忙

我找到了解决方案。 我仍然不确定为什么它没有更新,但是我得到它的工作方式是显式地在MenuItem对象上公开ForeignKey:

public class MenuItem : BaseModel
{    
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }        
    // I didn't have this exposed before //
    public int? UseSiblingClaim_Id { get; set; }
    public virtual MenuItem UseSiblingClaim { get; set; }
}

然后从以下位置更改我的映射:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<MenuItem>()
                .HasOptional(x=>x.UseSiblingClaim)                
                .WithOptionalDependent()
                .Map(m => m.MapKey("UseSiblingClaim_Id"));
    base.OnModelCreating(modelBuilder);
}

至:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{  
    modelBuilder.Entity<MenuItem>()
            .HasOptional(x => x.UseSiblingClaim)
            .WithMany()
            .HasForeignKey(x => x.UseSiblingClaim_Id);
    base.OnModelCreating(modelBuilder);
}

然后,在我的MenuItemController中,我只需要设置外键属性(UseSiblingClaim_Id),而不是导航属性,该属性也保存了db旅行。

答案被埋在这里: 无法获取关系以更新实体框架中的导航属性

我遇到了同样的问题。 我通过改变解决了

IEnumerable<Item>

ICollection<Item>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM