ASP.NET MVC编辑导航集合属性

时间:2015-03-27 11:48:30

标签: asp.net asp.net-mvc entity-framework

我正在尝试更新实体的集合导航属性,但我很确定我不会以正确的方式进行更新。在我的应用程序中,我创建了一个用户和角色模型,因为一个用户可以属于多个角色,角色可以有很多用户,我就这样建模了

为简报省略了一些字段的用户:

 public class User
{
    public int Id { get; set; }
    public string UserName { get; set; }
    public string Password { get; set; }

    public virtual ICollection<UserRole> UserHasRoles { get; set; } 
}

public class Role
{
    public int Id { get; set; }
    public string UserRole { get; set; }

    public virtual ICollection<UserRole> UserHasRoles { get; set; }
}

public class UserRole
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public int RoleId { get; set; }

    public User User { get; set; }
    public Role Role { get; set; }
}

我制作了一个我给视图的视图模型,以便您可以为用户选择新角色:

public class UserWithRoleViewModel
{
    public User User { get; set; }
    public List<Role> Roles { get; set; }
    public List<int> RoleIds { get; set; }
}

在我的控制器的[HttpPost]操作方法中收到视图模型后,我将其传递到我的存储库并尝试使用所选角色更新用户:

public void SaveChangesToUser(UserWithRoleViewModel model)
    {
        model.User.UserHasRoles = new List<UserRole>();

        foreach (var id in model.RoleIds)
        {
            model.User.UserHasRoles.Add(new UserRole { UserId = model.User.Id, RoleId = id });
        }
        _context.Entry(model.User).State = EntityState.Modified;
        _context.SaveChanges();
    }

我尝试清除导航属性中的旧值并插入新值,但它不起作用。更新其他用户属性可以正常工作,但不能导航属性。所以我的问题是,为什么这不起作用,我甚至试图以正确的方式做到这一点?

2 个答案:

答案 0 :(得分:0)

其实我把它拿回来,我看你在做什么,试试下面的代码

public void SaveChangesToUser(UserWithRoleViewModel model)
{
    model.User.UserHasRoles = new List<UserRole>();

    _context.Entry(model.User).State = EntityState.Modified;
    foreach (var id in model.RoleIds)
    {
        var userRole = new UserRole { UserId = model.User.Id, RoleId = id };
        model.User.UserHasRoles.Add(userRole);
        _context.Entry(userRole).State = EntityState.Added;
    }
    _context.SaveChanges();
}

我认为你必须设定所有孩子的状态。

另一个注意事项,我同意@Simon,你不需要UserRole对象,你可以只映射到db中的关联表,只在用户中有ICollection<Role>,在角色中只有ICollection<User>

你的地图中的

        HasMany(c => c.Users).WithMany(c => c.Roles).Map(r =>
        {
            r.MapLeftKey("RoleId");
            r.MapRightKey("UserId");
            r.ToTable("RoleUser");
        });

答案 1 :(得分:0)

对于实体框架中的多对多关系,您需要使用流畅的API并声明您的关系。 首先,关联类不应该拥有它自己的主键。

public class UserRole
{
    public int UserId { get; set; }
    public int RoleId { get; set; }

    public virtual User User { get; set; }
    public virtual Role Role { get; set; }
}

删除UserRole中的Id,UserId和RoleId将组成它的主要内容。既然模型设计得当,我们需要为关系创建模型构建器:

在您的databasecontext类中:

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
     base.OnModelCreating(modelBuilder);
     modelBuilder.Entity<UserRole>()
                        .HasKey(cp => new { cp.UserId, cp.RoleId })
                        .Map(q=>q.ToTable("UserRole")); //your database table name

     modelBuilder.Entity<User>()
                        .Map(q =>q.ToTable("User"))
                        .HasMany(c => c.UserRole)
                        .WithRequired()
                        .HasForeignKey(cp => cp.UserId) //points on the UserId in UserRole table
                        .WillCascadeOnDelete(); //should handle cascade deletes
     modelBuilder.Entity<Role>()
                        .Map(q =>q.ToTable("Role"))
                        .HasMany(c => c.UserRole)
                        .WithRequired()
                        .HasForeignKey(cp => cp.RoleId)
                        .WillCascadeOnDelete();
 } 

确保您的映射使用正确的表名。请注意,lambda中使用的名称是完全随机的,可能会根据您自己的需要进行更改。