简体   繁体   中英

How to avoid redundancy/save data in EF Core many-to-many relationships?

Can someone please answer me how to properly add and insert data into a join table/many-to-many relationship with Entity Framework Core, without saving data multiple times?

My Database Context looks like this with Fluent API:

protected override void OnModelCreating(ModelBuilder builder)
{
    builder.Entity<User>().HasIndex(u => u.Username).IsUnique(true);

     builder.Entity<GroupMembers>().HasKey(gm => new { gm.UserId, gm.GroupId });
     builder.Entity<GroupMembers>().HasOne(gm => gm.Group).WithMany(group.GroupMembers).HasForeignKey(gm => gm.GroupId);
     builder.Entity<GroupMembers>().HasOne(gm => gm.User).WithMany(user.GroupMembers).HasForeignKey(gm => gm.UserId);
}

Here are my models for User, Group and the join table between them:

public class User
{
    [Key]
    public Guid Id { get; set; }
    public string Username { get; set; }
    public List<GroupMembers> GroupMembers { get; set; } = new List<GroupMembers>();
}
public class Group
{
    [Key]
    public Guid Id { get; set; }
    public string GroupName { get; set; }
    public List<GroupMembers> GroupMembers { get; set; } = new List<GroupMembers>();
}
public class GroupMembers
{
    [Key]
    public Guid UserId { get; set; }
    public User User { get; set; }

    [Key]
    public Guid GroupId { get; set; }
    public Group Group { get; set; }
}

Now, the question is; how do I add a relationship between them/insert into the tabel GroupMembers? Is it like this?

public class DatabaseHelper : IDatabaseHelper
{
    private readonly AppDatabaseContext _databaseContext;

    private readonly AppDatabaseContext _databaseContext;

    GroupMembers groupMember = new GroupMembers
    {
        Group = group,
        GroupId = group.Id,
        User = user,
        UserId = user.Id
    };

    User user = ...
    Group group = ...

    user.GroupMembers.Add(groupMember);
    group.GroupMembers.Add(groupMember);

    _databaseContext.Users.Update(user);
    _databaseContext.Groups.Update(group);
    _databaseContext.SaveChanges();
}

If this is the correct solution, then isn´t it true that the data for group members will be saved two times eg. redundancy? Group has the information about its members, and User has information about its group memberships. With a normal RDBS the information about the memberships are saved in the join tables, namely GroupMembership only once, without any redundancy. How do I do this with EF Core many-to-many?

EDIT Should GroupMembers be a DbSet<>, or should only User and Group be a DbSet<>?

public class AppDatabaseContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Group> Groups { get; set; }
        //public DbSet<GroupMembers> GroupMembers{ get; set; }
    }
    ...
}

I think efcore tracker takes care of the situation and doesnt insert the record twice. If it doesnt you can insert your groupmember object into yourdatabase once, instead of updating both groups and users. Which is also better performance wise, since only requires one query.

isn´t it true that the data for group members will be saved two times eg. redundancy?

No. You properly set the key on GroupMember to prevent that:

builder.Entity<GroupMembers>().HasKey(gm => new { gm.UserId, gm.GroupId });

Is it like this?

Possibly, but the method with the least overhead is always to have a DbSet<GroupMember> . (Advice: don't use plural class names). Then all you need is two ID values:

var groupMember = new GroupMember
{
    GroupId = groupId,
    UserId = userId
};

_databaseContext.GroupMembers.Add(groupMember);
_databaseContext.SaveChanges();

This can be embedded in any use case. You may have cases where only ID values are supplied from a UI or an API, or where either a User or a Group is the starting point, supplying one ID value, and ID values of the other part are supplied. It all boils down to this little piece of code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM