ASP.. NET MVC实体框架6导航属性没有保存在SaveChanges()库模式在编辑

本文关键字:SaveChanges 存在 编辑 模式 保存 实体 MVC NET 框架 属性 导航 | 更新日期: 2023-09-27 18:05:36

我遇到了一个奇怪的问题,其中导航属性不是在页面的更新上持续存在,而是在创建上。我正在使用实体框架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();
    }
}

这里,Edit页面的Get基础使用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);
///....///
}

这个方法不起作用。正如您所看到的,正在通过id检索完整的对象UseSiblingClaim,并将其设置为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; }
    }

View部分(与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>

模型。创建了SiblingItems并将其传递给视图。

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

ASP.. NET MVC实体框架6导航属性没有保存在SaveChanges()库模式在编辑

我找到了一个解决方案。我仍然不确定为什么它没有更新,但我让它工作的方式是在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>