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);
```
asked Jun 18, 2020 at 15:15
\$\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.

answered Jun 18, 2020 at 15:25
\$\endgroup\$
4
  • \$\begingroup\$ Good point about .Ignore, will do that \$\endgroup\$ Commented 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\$ Commented Jun 18, 2020 at 15:44
  • \$\begingroup\$ I would project to a UserDto with a UserOrganizationOutputDto \$\endgroup\$ Commented 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\$ Commented Jun 18, 2020 at 15:45

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.