EF Core Many-to-Many Relation Table Naming [duplicate] - entity-framework

This question already has answers here:
Change name of generated Join table ( Many to Many ) - EF Core 5
(2 answers)
Closed 1 year ago.
Does EF Core provide a way of naming the many-to-many relations mapping to database tables ?
In a code-first pattern, I have the following 2 Entities:
[Table("Prefix.Users")]
public class User
{
public int ID { get; set; }
public IEnumerable<Role> Roles { get; set; }
}
[Table("Prefix.Roles")]
public class Role
{
public int ID { get; set; }
public IEnumerable<User> Users { get; set; }
}
I've skipped the detailed Entity structure here. The ID properties in User & Role are keys (Database generated Identity)
User and Role entities share a many-to-many relationship.
EF Core generates a third table in Database with Table name UsersRoles
Is there a way I can add a prefix to the 3rd table name so it becomes Prefix.UsersRoles without manually adding a third Entity UserRoles that maps User and Role and giving it the desired name with Prefix

Use fluent API instead of using data annotations
Your model classes should be like this.
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public virtual ICollection<UserRole> UserRoles { get; set; }
}
public class Role
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<UserRole> UserRoles { get; set; }
}
public class UserRole
{
public int UserId { get; set; }
public int RoleId { get; set; }
public virtual User User { get; set; }
public virtual Role Role { get; set; }
}
Your fluent api configuration classes like be this
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("User");
builder.HasKey(x => x.Id);
}
}
public class RoleConfiguration : IEntityTypeConfiguration<Role>
{
public void Configure(EntityTypeBuilder<Role> builder)
{
builder.ToTable("Role");
builder.HasKey(x => x.Id);
}
}
public class UserRoleConfiguration : IEntityTypeConfiguration<UserRole>
{
public void Configure(EntityTypeBuilder<UserRole> builder)
{
builder.ToTable("UserRole");
builder.HasKey(x => new { x.UserId, x.RoleId });
builder
.HasOne<Role>(s => s.Role)
.WithMany(r => r.UserRoles)
.HasForeignKey(s => s.RoleId).OnDelete(DeleteBehavior.Restrict);
builder
.HasOne<User>(s => s.User)
.WithMany(r => r.UserRoles)
.HasForeignKey(s => s.UserId).OnDelete(DeleteBehavior.Restrict);
}
}
Your DbContext class should be like this
public class MyDbContext : DbContext
{
public EEGDbContext()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(#"Server=xxxx;Database=DB;User Id=sa;Password=xxxxx;");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new UserConfiguration());
modelBuilder.ApplyConfiguration(new RoleConfiguration());
modelBuilder.ApplyConfiguration(new UserRoleConfiguration());
base.OnModelCreating(modelBuilder);
}
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<UserRole> UserRoles { get; set; }
}

Related

How to map many-to-many with Code First to same class?

I use Code First with Entity Framework 5.
I have User class, where one user can be friends with many people.
public class User
{
[Key]
public Guid UserID { get; set; }
public virtual ICollection<User> Friends { get; set; }
}
This however maps 0..1-to-many. How should I map many-to-many relationship with the same class in Code First?
Add configuration class:
public class UserConfiguration : EntityTypeConfiguration<User>
{
public UserConfiguration()
{
HasMany(u => u.Friends).WithMany();
}
}
then, this needs to be added to context class
public class MyContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserConfiguration());
base.OnModelCreating(modelBuilder);
}
}
public class Organization : Entity
{
public string Name { get; set; }
public string Description { get; set; }
public virtual Organization Parent { get; set; }
public virtual ICollection<Organization> Children { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class OrganizationConfiguration : EntityMapperBase<Organization>
{
public OrganizationConfiguration()
{
HasKey(f => f.Id);
Property(f => f.Name).HasMaxLength(20).IsRequired();
HasMany(f => f.Children).WithOptional(f => f.Parent).Map(m => m.MapKey("ParentId")).WillCascadeOnDelete(false);
HasMany(f => f.Users).WithRequired(f => f.Organization).Map(m => m.MapKey("OrganizationId"));
}
}
may it help you
You should have tow navigation properties
public class User
{
[Key]
public Guid UserID { get; set; }
public virtual ICollection<User> FriendsOfMine { get; set; }
public virtual ICollection<User> FriendsWithMe { get; set; }
}

How do I force generated many-to-many Relation tables to the correct schema?

I have tables parkpay.User and parkpay.Role. EF Code First automatically generates a third table linking the two for a many-to-many relationship, but it generates dbo.UserRole. How do I get it to make that table `parkpay.UserRole'?
Use EntityTypeConfiguration<> config many-to-many mappings.
public class User
{
public long Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
public class Role
{
public long Id { get; set; }
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class UserMapping : EntityTypeConfiguration<User>
{
public UserMapping()
{
ToTable("User", "parkpay");
HasKey(e => e.Id).Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasMany(e => e.Roles).WithMany(e => e.Users).Map(m => m.ToTable("UserRole", "parkpay").MapLeftKey("RoleId").MapRightKey("UserId"));
}
}
public class RoleMapping : EntityTypeConfiguration<Role>
{
public RoleMapping()
{
ToTable("Role", "parkpay");
HasKey(e => e.Id).Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
public class DatabaseContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserMapping());
modelBuilder.Configurations.Add(new RoleMapping());
base.OnModelCreating(modelBuilder);
}
}

Entity Framework Code First Membership Provider Relationship Issue

I'm trying to code first on asp.net membership provider. When code first creates the table, it generates all tables and appropriate relationship to the bridge table but it also create an additional relationship from the AspNet_User(one) to Aspnet_Role(many). Do you know why it doing this? There shouldn't be any relationship between user and role table.
public class Aspnet_Role
{
public Aspnet_Role()
{
Aspnet_Users = new HashSet<Aspnet_Users>();
}
[Key]
public Guid RoleId { get; set; }
public string RoleName { get; set; }
public string LoweredRoleName { get; set; }
public string Description { get; set; }
public virtual ICollection<Aspnet_Users> Aspnet_Users { get; set; }
}
public class Aspnet_Users
{
public Aspnet_Users()
{
Aspnet_Roles = new HashSet<Aspnet_Role>();
}
[Key]
public Guid UserId { get; set; }
public string UserName { get; set; }
public string LoweredUserName { get; set; }
public string MobileAlias { get; set; }
public bool IsAnonymous { get; set; }
public DateTime LastActivityDate { get; set; }
public virtual Aspnet_Membership Aspnet_Membership { get; set; }
public virtual ICollection<Aspnet_Role> Aspnet_Roles { get; set; }
}
public class StagingContext : DbContext
{
public DbSet<Aspnet_Role> Aspnet_Roles { get; set; }
public DbSet<Aspnet_Users> Aspnet_Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Aspnet_Users>()
.HasMany(r => r.Aspnet_Roles)
.WithMany()
.Map(m => m.ToTable("aspnet_UsersInRoles")
.MapRightKey("RoleId")
.MapLeftKey("UserId"));
}
}
I added the navigation property on the WithMany extension.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Aspnet_Users>()
.HasMany(r => r.Aspnet_Roles)
.WithMany(u => u.Aspnet_Users)
.Map(m => m.ToTable("aspnet_UsersInRoles")
.MapRightKey("RoleId")
.MapLeftKey("UserId"));
}

Entity Framework 5 using multiple relationships between two POCOs

I'm having issues applying multiple relationships (or possibly foreignkey) on two POCO objects. I've got the first relationship many-to-many working and when the database is created it creates the three tables (Projects, Users and ProjectsUsers) needed for the relationship.
Code so far:
public class Project
{
public int ProjectId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? CompletionDate { get; set; }
public bool Deleted { get; set; }
public ICollection<User> Users { get; set; }
}
public class User
{
public User()
{
Name = new Name();
}
public int UserId { get; set; }
public string LoginId { get; set; }
public string Password { get; set; }
public Name Name { get; set; }
public ICollection<Project> ManagedProjects { get; set; }
}
public class ProjectConfiguration : EntityTypeConfiguration<Project>
{
public ProjectConfiguration()
{
HasMany(x => x.Users)
.WithMany(x => x.ManagedProjects);
}
}
public UserConfiguration()
{
HasMany(x => x.ManagedProjects)
.WithMany(x => x.Users);
}
Now I want to add an optional one-to-one relationship of Project.ManagingUser -> User. However, I can't seem to figure out how to indicate this in the configuration.
Code for what I think is needed:
public class Project
{
public int ProjectId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? CompletionDate { get; set; }
public bool Deleted { get; set; }
public int? ManagingUserId { get; set; }
public User ManagingUser { get; set; }
public ICollection<User> Users { get; set; }
}
I don't think the User object needs to change.
This shows my last attempt on mapping the new relationship:
public ProjectConfiguration()
{
HasMany(p => p.Users)
.WithMany(u => u.Projects);
this.HasOptional(p => p.ManagingUser)
.WithOptionalDependent()
.Map(m=>m.MapKey("ManagingUserId"))
.WillCascadeOnDelete(false);
}
What is happening when the database is created, I now end up with only two tables (Projects and Users). And it looks like it is only trying to setup the one-to-one relationship.
Can someone tell me what I'm missing?
Richard I've not changed the UserConfiguration and below is the DbContext:
public class MyDbContext : DbContext
{
public MyDbContext() : base(Properties.Settings.Default.ConnectionString)
{
}
public DbSet<User> Users { get; set; }
public DbSet<Project> Projects { get; set; }
}
You probably want WithMany instead of WithOptionalDependent - it's a one:many relationship, not a one:one.
HasOptional(p => p.ManagingUser)
.WithMany()
.HasForeignKey(m => m.ManagingUserId)
.WillCascadeOnDelete(false);
EDIT
I think you're missing the OnModelCreating override from the DbContext class:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new ProjectConfiguration());
modelBuilder.Configurations.Add(new UserConfiguration());
}

Entity Framework 4.1 : The navigation property 'BusinessUser' declared on type 'Login' has been configured with conflicting multiplicities

I am having two entities
BusinessUser { Id(PK), Name,...}
Login { BusinessUserID(PK, FK), Email, Password, etc...}
Relationship between BusinessUser and Login is one-to-zero/one.
I am having following configurations
In BusinessUser EF configuration class
this.HasOptional(bu => bu.LoginInfo)
.WithOptionalPrincipal(l => l.BusinessUser);
In Login EF configuration class
this.HasRequired(l => l.BusinessUser)
.WithOptional(bu => bu.LoginInfo);
I am getting following exception
The navigation property 'BusinessUser' declared on type 'Login' has been configured
with conflicting multiplicities.
Where I am wrong with my one-to-one/zero configuration in EF 4.1 code first.
Update 1 : Following are my class structure
public class BusinessUser {
public virtual int ID { get; set; }
public virtual int BusinessID { get; set; }
public virtual Business Business { get; set; }
public Login LoginInfo { get; set; }
}
public class Login {
public virtual int BusinessUserID { get; set; }
public virtual string Email { get; set; }
public virtual string Password { get; set; }
public BUsinessUser BusinessUserInfo { get; set; }
}
Also I am looking for bi-directional.
Your BusinessUser must have relation configured as:
this.HasOptional(bu => bu.LoginInfo)
.WithRequired(l => l.BusinessUser);
Both configuration must be same (actually only one is needed) and the first configuration is incorrect because it is trying to define 0..1 - 0..1 relation.
How have you structured your classes ? Here's a sample with a relationship one-to-one/zero defined.
The result is :
BusinessUser { Id(PK), Name,...}
Login { BusinessUserID(PK, FK), Email, Password, etc...}
public class BusinessUser
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public virtual LoginInfo LoginInfo { get; set; }
}
public class LoginInfo
{
public int BusinessUserId { get; set; }
public virtual BusinessUser BusinessUser { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
Here is the DbContext and the Initializer
public class MyContext : DbContext
{
public DbSet<BusinessUser> BusinessUsers { get; set; }
public DbSet<LoginInfo> LoginInfos { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
//We define the key for the LoginInfo table
modelBuilder.Entity<LoginInfo>().HasKey(x => x.BusinessUserId);
modelBuilder.Entity<LoginInfo>().HasRequired(bu => bu.BusinessUser);
}
}
public class MyInitializer : DropCreateDatabaseIfModelChanges<MyContext>
{
protected override void Seed(MyContext context)
{
var businessUser = new BusinessUser();
businessUser.Email = "mymail#email.com";
businessUser.Name = "My Name";
businessUser.LoginInfo = new LoginInfo(){Username = "myusername", Password ="mypassword"};
context.BusinessUsers.Add(businessUser);
context.SaveChanges();
}
}