Pregunta

I'm have this Many To Many Relationship:

public class Role
{
    [Key]
    public int role_Id { get; set; }
    public string Name { get; set; }
    public ICollection<LoginModel> Users { get; set; }

    public ICollection<Permission> Permissions { get; set; }

    public Role()
    {
        Users = new List<LoginModel>();
        Permissions = new Collection<Permission>();

    }
}

public class Permission
{
    [Key]
    public int permi_Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Role> Roles { get; set; }

    public Permission()
    {
        Roles = new Collection<Role>();
    }
}

In my DbContext

modelBuilder.Entity<Role>().HasMany(r => r.Permissions).WithMany(p => p.Roles)
                .Map(
                    m =>
                    {
                        m.MapLeftKey("role_id");
                        m.MapRightKey("per_id");
                        m.ToTable("roles_permissions");
                    }
                );

So I have this third table (Many To Many) and I want to Update the permissions (Add or remove) for a specific Role ( The permissions are taken from a CheckedListBox).I'm trying to update the third table with this code but it does not work

//Get the specific role

Role role = (from s in db.Roles
             where s.Name == txt_modificar_nombre.Text
             select s).FirstOrDefault<Role>();

//Get the permissions from that specific role

var permissions = db.Roles.Where(r => r.Name == txt_modificar_nombre.Text)
                 .SelectMany(r => r.Permissions);

//erase all the old permissions (like reset the permissions)

foreach (var permission in permissions)
{
    role.Permissions.Remove(permission);//reset the permissions
    for (int i = 0; i < checkedListBox_modificar_permissions.Items.Count; i++)
    {
        if ((string)checkedListBox_modificar_permissions.Items[i] == permission.Name)
        {
            checkedListBox_modificar_permissions.SetItemChecked(i, true);
        }
    }
}

//Insert the new permissions (checked=true in the checkedList)

foreach (var item in checkedListBox_modificar_permissions.CheckedItems)
{
    Permission permission = HandyClass.GetPermission(item.ToString(), db);
    role.Permissions.Add(permission);
    db.SaveChanges();
}  

I get this error in the line db.SaveChanges();

An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.

¿Fue útil?

Solución

The problem is that the collection role.Permissions is not loaded before you make changes to it. This is because

  1. It cant't be lazy loaded. To enable lazy loading, add the virtual modifier:

    public virtual ICollection<Permission> Permissions
    
  2. It isn't loaded eagerly, which can be done by Include:

    from s in db.Roles.Include(r => r.Permissions) ...
    

So you should do either of these, or both. Eager loading is preferred, because it grabs the data in one query.

The exception isn't too clear. It refers to case where entities don't have primitive foreign key properties, only collections and references to objects. But this only applies to 1-n associations. In the classical Order-Orderline association, Orderline may have

public virtual Order Order { get; set; }

which makes this an independent association

and also

[ForeignKey("Order"]
public virtual int OrderId { get; set; }

which turns it into a foreign key association.

But in a many-to-many association the entities can't have these primitive properties, because the foreign keys are in the hidden junction table roles_permissions. EF could give a more descriptive exception message here.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top