Relationship Problem Many to Many in the Entity Framework

Asked

Viewed 1,271 times

6

I have the following situation:

To perform an authentication, I’m using the old method for a small application, for assigning levels (roles), as many examples are found all over the web. Use EF and Postgres for accessing/recording data and Fluent API for relationship Many-to-Many Follows the models and the 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 recover the levels of a certain user, the Count (list) is reset. Detail that entered some data in the table manually in the database nivel_usuarios.

After some research, I found something that worked, but the author of the article used the nhibernate instead of EPH, follow:

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 understand through the property Bag, he did the relationship/mapping of the tables. Someone could help me identify where I am missing to make it work with the EPH?

When I give a post in the form, level comes null (he’s a checkbox):

Debug

Edit:

My view is like this:

@for (var i = 0; i < Model.Niveis.Count; i++)
            {
                <li class="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>
            }

1 answer

5


This approach of creating the associative table using the ModelBuilder is somewhat problematic. In its place, 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 association table and better control the inserts, which need not be manual.

[Index], introduced in this form from the Entity Framework 6.1.0, ensures the uniqueness of the associative record. Additional validations may be required in the application to avoid strange key duplicity errors for the user.

  • Hmm, sounds promising your reply Gypsy... I do not know would be very annoying, but why create associative table with Fluentapi is problematic? And another, you can no longer standardize the User Lists even in the Level and User classes?

  • 1

    I solved here Gypsy, now it worked "like a Charm". About the checkbox not coming to the controller is that in Hidden where I pass the id, I was passing with the initial letter capitalized, and in the controller was miniscula.

  • Come on. At the beginning of my days programming in ASP.NET MVC + EF (at the time was the 5, if I’m not mistaken), I used this notation. Then came two problems: 1) How do I control the association (add and delete) efficiently? 2) If I just want data about the associations themselves, how I mapped it into a DbSet<>? 3) If I want to put additional fields in the association, how can I do it? In short, the Fluent API does not meet any of these 3 points.

  • @Ciganomorrisonmendez se puder acesso: http://answall.com/questions/115336/entity-framework-many-to-many-ientitychangetracker-erro-como-resolver that is, if I add the dbset<> that you suggest here, I end up with two "equal" tables. What would be the solution?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.