Many to Many relationship problem in the Entity Framework

6

I have the following situation:

To perform an authentication, I am using the old method for a small application, for assigning levels (roles), as many examples that have the web apart. I use EF and Postgres to access / write data and the Fluent API to make the relationship many-to-many Follow the templates and context:

User

    [Table("usuarios", Schema = "public")]
    public class Usuario
    {
        [Key]
        public int usuarioid { get; set; }
        public string descricao { get; set; }
        public string nome { get; set; }
        public string senha { get; set; }

        public IList<Nivel> Niveis { get; set; }

        public Usuario()
        {
            Niveis = new List<Nivel>();
        }
    }

Level

[Table("niveis", Schema = "public")]
public class Nivel
{
    [Key]
    public int nivelid { get; set; }
    public string nome { get; set; }    
}

Datacontext

    public class EntidadeDB: DbContext
    {
        public EntidadeDB() : base(nameOrConnectionString: "Conexao") { }

        public DbSet<Usuario> Usuario { get; set; }
        public DbSet<Nivel> Nivel { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Usuario>()
                .HasMany<Nivel>(u => u.Niveis)
                .WithMany()
                .Map(cs =>
                    {                           
                        cs.MapLeftKey("nivelid");
                        cs.MapRightKey("usuarioid");
                        cs.ToTable("nivel_usuarios");
                    });
        }
    }

The problem is that when I try to record or retrieve the levels of a particular user, the count (list) is zeroed. Detail that I manually inserted some data into the database into the nivel_usuarios table.

After some research, I found something that worked, but the author of the article used nHibernate instead of EF , below:

User

public class User
{

    public virtual int Id { get; set; }
    public virtual string Username { get; set; }
    public virtual string Email { get; set; }
    public virtual IList<Role> Roles { get; set; }

    public User()
    {
        Roles = new List<Role>();
    }

}

public class UserMap : ClassMapping<User>
{
    public UserMap()
    {
        Table("users");

        Id(x => x.Id, x => x.Generator(Generators.Identity));

        Property(x => x.Username, x => x.NotNullable(true));
        Property(x => x.Email, x => x.NotNullable(true));

        Bag(x => x.Roles, x =>
        {
            x.Table("role_users");
            x.Key(k => k.Column("user_id"));
        }, x => x.ManyToMany(k => k.Column("role_id")));
    }
}

From what I understood through the Bag property, he did the relationship / mapping of the tables. Could someone help me identify where I'm going to make it work with EF ?

When I give post in form, level comes null (it's a checkbox ):

Edit:

Myviewlookslikethis:

@for(vari=0;i<Model.Niveis.Count;i++){<liclass="list-group-item">
                    @Html.Hidden("Niveis[" + i + "].Id", Model.Niveis[i].id)
                    <label for="Niveis_@(i)__IsChecked">
                        @Html.CheckBoxFor(m => m.Niveis[i].IsChecked)
                        @Model.Niveis[i].nome
                    </label>
                </li>
            }
    
asked by anonymous 26.11.2015 / 17:52

1 answer

5

This approach of creating the associative table using ModelBuilder is somewhat problematic. In its place, it would make an associative table and would not use Fluent API :

public class UsuarioNivel
{
    [Key]
    public int usuarionivelid { get; set; }
    [Index("IUQ_UsuarioNivel_UsuarioId_NivelId", IsUnique = true, Order = 1)]
    public int usuarioid { get; set; }
    [Index("IUQ_UsuarioNivel_UsuarioId_NivelId", IsUnique = true, Order = 2)]
    public int nivelid { get; set; }

    public virtual Usuario Usuario { get; set; }
    public virtual Nivel Nivel { get; set; }
}

I would also make some modifications:

[Table("usuarios", Schema = "public")]
public class Usuario
{
    [Key]
    public int usuarioid { get; set; }
    public string descricao { get; set; }
    public string nome { get; set; }
    public string senha { get; set; }

    public virtual ICollection<UsuarioNivel> UsuarioNiveis { get; set; }
}

[Table("niveis", Schema = "public")]
public class Nivel
{
    [Key]
    public int nivelid { get; set; }
    public string nome { get; set; }    

    public virtual ICollection<UsuarioNivel> UsuarioNiveis { get; set; }
}

This ensures that you can manipulate the join table and better control inserts, which do not have to be manual.

[Index] , introduced in this form from the Entity Framework 6.1.0, guarantees the uniqueness of the associative register. Additional validations may be required in the application to avoid extraneous errors of key duplication for the user.

    
26.11.2015 / 20:18