I use Identity 2.0. I have CustomUserRole
public class CustomUserRole : IdentityUserRole<long>
{
}
When i try generate a migration all is good. But if i add a configuration to CustomUserRole
public class CustomRoleConfiguration : EntityTypeConfiguration<CustomRole>
{
public CustomRoleConfiguration()
{
Property(r => r.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
EF adds a field CustomRole_Id
CreateTable(
"dbo.AspNetUserRoles",
c => new
{
UserId = c.Long(nullable: false),
RoleId = c.Long(nullable: false),
CustomRole_Id = c.Long(),
})
.PrimaryKey(t => new { t.UserId, t.RoleId })
.ForeignKey("dbo.AspNetUsers", t => t.UserId, cascadeDelete: true)
.ForeignKey("dbo.CustomRoles", t => t.CustomRole_Id)
.Index(t => t.UserId)
.Index(t => t.CustomRole_Id);
Now i have two field for Role. I dont understand why.
I had to write
base.OnModelCreating(modelBuilder);
after
modelBuilder.Configurations.Add(new DocumentConfiguration());
modelBuilder.Configurations.Add(new SubvisionConfiguration());
modelBuilder.Configurations.Add(new DocumentActionConfiguration());
modelBuilder.Configurations.Add(new CustomRoleConfiguration());
while i write it before
Related
I'm trying to add an entity to one of my tables but an error occurred. You can find below model, controller and output debug:
noting that I'm using this approach in my entire project and there is no problem, i don't know why he called the applicationUserId it's not in the related model...
model:
public class Rate
{
public int Id { get; set; }
public int ProjectId { get; set; }
[ForeignKey("ProjectId")]
public Projects Project { get; set; }
}
Controller:
var rate = new Rate
{
ProjectId = CPVM.Id,
};
rateRepository.Add(rate);
Rep:
public void Add(Rate entity)
{
db.Rate.Add(entity);
db.SaveChanges();
}
debugger output:
Microsoft.EntityFrameworkCore.Database.Command: Error: Failed executing DbCommand (2ms) [Parameters=[#p0='?' (Size = 450), #p1='?' (DbType = Int32), CommandType='Text', CommandTimeout='30']
INSERT INTO [Rate] ([ApplicationUserId], [ProjectId])
VALUES (#p0, #p1);
DBContext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<ApplicationUser>().ToTable("Users");
builder.Entity<IdentityRole>().ToTable("Roles");
builder.Entity<IdentityUserClaim<string>>().ToTable("UserClaims");
builder.Entity<IdentityUserRole<string>>().ToTable("UserRoles");
builder.Entity<IdentityUserLogin<string>>().ToTable("Userlogins");
builder.Entity<IdentityRoleClaim<string>>().ToTable("RoleClaims");
builder.Entity<IdentityUserToken<string>>().ToTable("UserTokens");
builder.Entity<Bids>()
.HasKey(b => b.Id);
builder.Entity<Languages>()
.HasKey(l => l.Id);
builder.Entity<Rate>()
.HasKey(r => r.Id);
builder.Entity<Projects>()
.HasKey(p => p.Id);
builder.Entity<TranslatorsLanguages>()
.HasKey(t => t.Id);
builder.Entity<TranslatorsLanguages>()
.HasOne(p => p.Languages)
.WithMany(b => b.TranslatorsLanguagesList)
.HasForeignKey(b => b.FromLanguage);
builder.Entity<TranslatorsLanguages>()
.HasOne(p => p.Languages)
.WithMany(b => b.TranslatorsLanguagesList)
.HasForeignKey(b => b.ToLanguage);
builder.Entity<TranslatorsLanguages>()
.HasOne(p => p.ApplicationUser)
.WithMany(b => b.TranslatorLanguagesList)
.HasForeignKey(b => b.TranslatorId);
builder.Entity<Projects>()
.HasOne(p => p.ApplicationUser)
.WithMany(b => b.ProjectsList)
.HasForeignKey(b => b.CustomerId);
builder.Entity<Projects>()
.HasOne(p => p.Languages)
.WithMany(b => b.ProjectsList)
.HasForeignKey(b => b.FromLanguage);
builder.Entity<Projects>()
.HasOne(p => p.Languages)
.WithMany(b => b.ProjectsList)
.HasForeignKey(b => b.ToLanguage);
builder.Entity<Bids>()
.HasOne(p => p.ApplicationUser)
.WithMany(b => b.BidsList)
.HasForeignKey(b => b.TranslatorId);
builder.Entity<Bids>()
.HasOne(p => p.Projects)
.WithMany(b => b.BidsList)
.HasForeignKey(b => b.ProjectId);
}
public DbSet<Languages> Languages { get; set; }
public DbSet<Projects> Projects { get; set; }
public DbSet<Rate> Rate { get; set; }
public DbSet<TranslatorsLanguages> TranslatorsLanguages { get; set; }
public DbSet<Bids> Bids { get; set; }
}
I found that in the applicationUser model there is a reference for Rate model public List<Rate> RateList { get; set; } when i removed it, it works!!
These are my tables:
Is there a standard way to apply the DELETE ON CASCADE between them ?
In one-to-many relationship I had no problem, but in this case I had to manually remove with a method written by me.
As you showed on the picture you have only two tables. It is not possible to set relationship between them as many-to-many (only if you will add new columns to this tables when new pairs will appear, but this is very bad practice). You should create third table, which will contain pairs of their primary keys. And at your migration you will be able to specify cascadeDelete to true between each of main tables and this third one. See below:
Models:
public class BugReport
{
public BugReport()
{
dublicates = new HashSet<DublicateBugReport>();
}
public int ID { get; set; }
public virtual ICollection<DublicateBugReport> dublicates { get; set; }
}
public class DublicateBugReport
{
public DublicateBugReport()
{
reports = new HashSet<BugReport>();
}
public int ID { get; set; }
public virtual ICollection<BugReport> reports { get; set; }
}
Piece of Migration:
public override void Up()
{
CreateTable(
"BugReports",
c => new
{
ID = c.Int(nullable: false, identity: true),
})
.PrimaryKey(t => t.ID) ;
CreateTable(
"DublicateBugReports",
c => new
{
ID = c.Int(nullable: false, identity: true),
})
.PrimaryKey(t => t.ID) ;
CreateTable(
"DublicateBugReportBugReports",
c => new
{
DublicateBugReport_ID = c.Int(nullable: false),
BugReport_ID = c.Int(nullable: false),
})
.PrimaryKey(t => new { t.DublicateBugReport_ID, t.BugReport_ID })
//pay attention! - cascadeDelete: true
.ForeignKey("DublicateBugReports", t => t.DublicateBugReport_ID, cascadeDelete: true)
.ForeignKey("BugReports", t => t.BugReport_ID, cascadeDelete: true)
.Index(t => t.DublicateBugReport_ID)
.Index(t => t.BugReport_ID);
}
I have a solution that I have been creating for a while and I have used EF Code First migrations to create the database. Recently for another solution my supervisor ran some scripts on the database that added a few tables. Now, I need to connect to those tables in my solution. I have this code here:
public class RoleMap : EntityTypeConfiguration<Role>
{
public RoleMap()
{
//Primary key
this.HasKey(t => t.RoleId);
this.Property(t => t.ApplicationId)
.IsRequired();
this.Property(t => t.Description)
.HasMaxLength(256);
this.Property(t => t.RoleName)
.IsRequired()
.HasMaxLength(256);
this.Property(t => t.LoweredRoleName)
.IsRequired()
.HasMaxLength(256);
this.ToTable("aspnet_Roles");
this.Property(t => t.RoleId).HasColumnName("RoleId");
this.Property(t => t.ApplicationId).HasColumnName("ApplicationId");
this.Property(t => t.Description).HasColumnName("Description");
this.Property(t => t.LoweredRoleName).HasColumnName("LoweredRoleName");
this.Property(t => t.RoleName).HasColumnName("RoleName");
}
}
static DataContext()
{
Database.SetInitializer<DataContext>(null);
}
public DataContext(): base("DefaultConnection")
{
}
public DbSet<Role> Roles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new RoleMap());
}
I found this code in this link:
http://www.codeproject.com/Tips/661053/Entity-Framework-Code-First-Map
Unfortunately, when I try to create a new migration - it is trying to create a new table (even though I told it the table already exists).
public partial class addRoles : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.aspnet_Roles",
c => new
{
RoleId = c.Guid(nullable: false),
ApplicationId = c.Guid(nullable: false),
Description = c.String(maxLength: 256),
LoweredRoleName = c.String(nullable: false, maxLength: 256),
RoleName = c.String(nullable: false, maxLength: 256),
})
.PrimaryKey(t => t.RoleId);
}
public override void Down()
{
DropTable("dbo.aspnet_Roles");
}
}
With the help of JamieD77 I found the solution. It is a combination of the code first mapping found in this link:
Code First Mapping
and then here, add -ignorechanges when add-migration
Code First Migrations With Existing Table
I am using EntityFramework and ASP.NET identity. I have derived from IdentityUser and IdentityGroup to store extra fields for my application.
I want to call properties: User.Groups and Group.Users, a many-to-many relationship, and have EntityFramework automatically create the linking table, GroupUsers.
My first attempt had the following:
public class ApplicationUser : IdentityUser
{
public string FullName { get; set; }
public virtual ICollection<ApplicationGroup> Groups { get; set; }
// ...
}
public class ApplicationGroup : IdentityGroup<ApplicationUser>
{
public virtual ICollection<ApplicationGroupRole> Roles { get; set; }
}
public class IdentityGroup<TUser, TKey> : IGroup<TKey>
where TUser : IdentityUser
where TKey : IEquatable<TKey>
{
public virtual ICollection<TUser> Users { get; set; }
// ...
}
And the DBMigration looked something like
CreateTable(
"UMS.ApplicationGroupApplicationUsers",
c => new
{
ApplicationGroup_Id = c.String(nullable: false, maxLength: 128),
ApplicationUser_Id = c.String(nullable: false, maxLength: 128),
})
.PrimaryKey(t => new { t.ApplicationGroup_Id, t.ApplicationUser_Id })
.ForeignKey("UMS.ApplicationGroups", t => t.ApplicationGroup_Id, cascadeDelete: true)
.ForeignKey("UMS.Users", t => t.ApplicationUser_Id, cascadeDelete: true)
.Index(t => t.ApplicationGroup_Id)
.Index(t => t.ApplicationUser_Id);
In particular, note the linking table has two indexes, one for each foreign key.
However, I wanted to name the linking table explicitly, so in my DBContext I added:
modelBuilder.Entity<ApplicationUser>().ToTable("Users");
modelBuilder.Entity<ApplicationGroup>().ToTable("Groups")
.HasMany(x => x.Users)
.WithMany(x => x.Groups)
.Map(x =>
{
x.ToTable("GroupUsers");
x.MapLeftKey("UserId");
x.MapRightKey("GroupId");
});
However, this gives me an automatic migration with only 1 index:
CreateTable(
"UMS.GroupUsers",
c => new
{
UserId = c.String(nullable: false, maxLength: 128),
GroupId = c.String(nullable: false, maxLength: 128),
})
.PrimaryKey(t => new { t.UserId, t.GroupId })
.ForeignKey("UMS.Groups", t => t.UserId, cascadeDelete: true)
.ForeignKey("UMS.Users", t => t.GroupId, cascadeDelete: true)
.Index(t => t.UserId);
Is this just a bug in EntityFramework? This appears to only happen when one type has a collection of the other via a derived type. Is it possible to keep an explicitly named linking table whilst automatically creating both indexes?
This may not resolve the problem you are having, however, it will correct your code. In your case, as per definition, the "Left Key" should be "GroupId" and the "Right Key" should be "UserId". Check this link. Notice the code you posted, you have got them mixed:
.ForeignKey("UMS.Groups", t => t.UserId, cascadeDelete: true)
.ForeignKey("UMS.Users", t => t.GroupId, cascadeDelete: true)
Your code should look like this:
modelBuilder.Entity<ApplicationGroup>().ToTable("Groups")
.HasMany(x => x.Users)
.WithMany(x => x.Groups)
.Map(x =>
{
x.ToTable("GroupUsers");
x.MapLeftKey("GroupId");
x.MapRightKey("UserId");
});
I have two tables that are connect N to N:
[Table("Backoffice_Roles")]
public class Role
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid RoleId { get; set; }
public ICollection<User> Users { get; set; }
}
[Table("Backoffice_Users")]
public class User
{
// Primary key
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid UserId { get; set; }
public ICollection<Role> Roles { get; set; }
}
This all works fine and it creates 3 tables: Backoffice_Roles, Backoffice_Users and RoleUsers.
Is there a way to rename RoleUsers to Backoffice_RoleUsers ?
I tried renaming the table manually in the migration file but it gives this error:
System.Data.Entity.Infrastructure.DbUpdateException: An error occurred
while saving entities that do not expose foreign key properties for
their relationships. The EntityEntries property will return null
because a single entity cannot be identified as the source of the
exception. Handling of exceptions while saving can be made easier by
exposing foreign key properties in your entity types. See the
InnerException for details. --->
System.Data.Entity.Core.UpdateException: An error occurred while
updating the entries. See the inner exception for details. --->
System.Data.SqlClient.SqlException: Invalid object name
'dbo.RoleUsers'.
This the migration without changing the name of the last table manually:
public override void Up()
{
CreateTable(
"dbo.Backoffice_Users",
c => new
{
UserId = c.Guid(nullable: false, identity: true),
})
.PrimaryKey(t => t.UserId);
CreateTable(
"dbo.Backoffice_Roles",
c => new
{
RoleId = c.Guid(nullable: false, identity: true),
})
.PrimaryKey(t => t.RoleId);
CreateTable(
"dbo.RoleUsers",
c => new
{
Role_RoleId = c.Guid(nullable: false),
User_UserId = c.Guid(nullable: false),
})
.PrimaryKey(t => new { t.Role_RoleId, t.User_UserId })
.ForeignKey("dbo.Backoffice_Roles", t => t.Role_RoleId)
.ForeignKey("dbo.Backoffice_Users", t => t.User_UserId)
.Index(t => t.Role_RoleId)
.Index(t => t.User_UserId);
}
Use following mapping to provide name for junction table:
modelBuilder.Entity<Role>()
.HasMany(r => r.Users)
.WithMany(u => u.Roles)
.Map(m => m.ToTable("Backoffice_RoleUsers"));
You can provide mappings by overriding OnModelCreating method of your DbContext class.