1
\$\begingroup\$

I've implemented Many-To-Many relationship and wonder if this is the optimal way for it. Since I do not have extensive EF Core experience I would love if someone with more experience could check it out.

Scenario:

  • Many users
  • Many organizations
  • User can belong to multiple organizations
  • Organization can hold multiple users
// Organization.cs
public class Organization
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public virtual IEnumerable<OrganizationUser> OrganizationUsers { get; set; }
}
// OrganizationUser.cs
public class OrganizationUser
{
    public Guid OrganizationId { get; set; }
    public virtual Organization Organization { get; set; }
    public Guid UserId { get; set; }
    public virtual User User { get; set; }

    public Role Role { get; set; }
}

public enum Role
{
    Owner,
    Admin,
    User
}

// User.cs
public class User
{
    public Guid Id { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
    public virtual IEnumerable<OrganizationUser> OrganizationUsers { get; set; }

    [NotMapped]
    public virtual IEnumerable<UserOrganizationOutputDto> Organizations
    {
        get
        {
            return OrganizationUsers.Select(x => new UserOrganizationOutputDto
            {
                Id = x.OrganizationId.ToString(),
                Name = x.Organization.Name,
                Role = x.Role
            });
        }
    }
}

// Database Context code that is related
modelBuilder.Entity<Organization>()
    .HasMany<OrganizationUser>()
    .WithOne(x => x.Organization);
modelBuilder.Entity<User>()
    .HasMany<OrganizationUser>()
    .WithOne(x => x.User);

modelBuilder.Entity<OrganizationUser>()
    .HasKey(x => new {x.OrganizationId, x.UserId});
modelBuilder.Entity<OrganizationUser>()
    .HasOne(x => x.User)
    .WithMany(x => x.OrganizationUsers)
    .HasForeignKey(x => x.UserId);
modelBuilder.Entity<OrganizationUser>()
    .HasOne(x => x.Organization)
    .WithMany(x => x.OrganizationUsers)
    .HasForeignKey(x => x.OrganizationId);

```
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Couple of pointers. You are mixing data notation and fluent mapping.

replace NotMapped attribute with .Ignore fluent mapping.

Also I think its cleaner to move each entity into its own mapping config class using IEntityTypeConfiguration<T>

Dont mix DTO and entities like that. Best practice is to project your entities to DTOs.

\$\endgroup\$
4
  • \$\begingroup\$ Good point about .Ignore, will do that \$\endgroup\$
    – sed
    Jun 18, 2020 at 15:30
  • \$\begingroup\$ You know, the reason I mix this DTO is that I need to get list of users and their respective role so this was the cleanest way I could imagine doing that. \$\endgroup\$
    – sed
    Jun 18, 2020 at 15:44
  • \$\begingroup\$ I would project to a UserDto with a UserOrganizationOutputDto \$\endgroup\$
    – Anders
    Jun 18, 2020 at 15:45
  • \$\begingroup\$ x.Organization.Name forces you to use include otherwise you will get null reference error. with projection its not needed. Alot cleaner. Best practice too \$\endgroup\$
    – Anders
    Jun 18, 2020 at 15:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.