AspNetUserRole table creating multiple columns in the database after customizing .NET - c#

I am using EF Core 5 and have extended EF Core Identity to manage user auth. But when I migrate my Entity objects to the database it creates extra columns in the database for example:
AspNetUserRole table creates 4 columns in the database UserId UserId1 RoleId RoleId1 in the database.
Here are my extended classes to give you more insights:
ASP.NET USER ENTITY:
public class AspNetUser : IdentityUser
{
public AspNetUser()
{
UserRoles = new List<AspNetUserRoles>();
AspNetUserShippingInfo = new List<AspNetUserShippingInfo>();
AspNetUserPaymentInfo = new List<AspNetUserPaymentInfo>();
}
public string FirstName { get; set; }
public string LastName { get; set; }
public string ExternalUserId { get; set; }
public string ExternalProviderName { get; set; }
public bool VerifiedEmail { get; set; }
[ForeignKey("Vendor")]
public int? VendorId { get; set; }
public virtual Vendor Vendor { get; set; }
//TODO: remove from here. doesn't belong here maybe
[ForeignKey("DeliveryCompany")]
public int? DeliveryCompanyId { get; set; }
public virtual DeliveryCompanies DeliveryCompany { get; set; }
public virtual IList<AspNetUserShippingInfo> AspNetUserShippingInfo { get; set; }
public virtual IList<AspNetUserPaymentInfo> AspNetUserPaymentInfo { get; set; }
public virtual IList<AspNetUserRoles> UserRoles { get; set; }
public int? PreferredZipCode { get; set; }
public string PreferredLanuage { get; set; }
}
ASP.NET ROLE ENTITY:
public class AspNetRoles : IdentityRole<string>
{
public AspNetRoles()
{
UserRoles = new List<AspNetUserRoles>();
}
public virtual IList<AspNetUserRoles> UserRoles { get; set; }
}
ASP.NET USER ROLE ENTITY:
public class AspNetUserRoles : IdentityUserRole<string>
{
public AspNetUserRoles() : base()
{
}
public override string UserId { get; set; }
[ForeignKey("UserId")]
public virtual AspNetUser User { get; set; }
public override string RoleId { get; set; }
[ForeignKey("RoleId")]
public virtual AspNetRoles Role { get; set; }
}
I'm not sure what I'm doing wrong that generates these extra columns in the database. any help will be highly appreciated. Thanks

You can do the following step to solve your issue.
1:change your AspNetUserRoles
public class AspNetUserRoles : IdentityUserRole<string>
{
public AspNetUserRoles() : base()
{
}
public override string UserId { get; set; }
public virtual AspNetUser User { get; set; }
public override string RoleId { get; set; }
public virtual AspNetRoles Role { get; set; }
}
2:In your context:
public class ApplicationDbContext : IdentityDbContext<AspNetUser, AspNetRoles, string,
IdentityUserClaim<string>, AspNetUserRoles, IdentityUserLogin<string>,
IdentityRoleClaim<string>, IdentityUserToken<string>>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//add this code,do not set a composite primary key.
modelBuilder.Entity<AspNetUser>(b =>
{
b.HasMany(e => e.UserRoles)
.WithOne(e => e.User)
.HasForeignKey(ur => ur.UserId)
.IsRequired();
});
modelBuilder.Entity<AspNetRoles>(b =>
{
b.HasMany(e => e.UserRoles)
.WithOne(e => e.Role)
.HasForeignKey(ur => ur.RoleId)
.IsRequired();
});
}
3:Remigration and update database.

If You Don't Include This Code Then Your Code Works Fine Your AspNetUserRoles Class Look Like This
public class AspNetUserRoles : IdentityUserRole<string>
{
public AspNetUserRoles() : base()
{
}
[Key]
public virtual AspNetUser User { get; set; }
[Key]
public virtual AspNetRoles Role { get; set; }
}
You Can Also Do Something Like This
public class AspNetUser : IdentityUser
{
public AspNetUser()
{
this.Role=new HashSet<AspNetRoles>();
}
public virtual ICollection<AspNetRoles> Role { get; set; }
}
public class AspNetRoles : IdentityRole<string>
{
public AspNetRoles()
{
this.User=new Hashest<AspNetUser>();
}
public virtual ICollection<AspNetUser> User { get; set; }
}
If you Go With Second Option Then You don't Need To add Extra Class AspNetUserRoles for Many To Many Relationship
Just Try This Last code it working Fine in my computer
public class AspNetRoles
{
public string RoleId { get; set; }
public string USerId { get; set; }
}

Related

EF multiple foreign key relationship on same primary key ApplicationUser table

I want to create a one-to-many relationship using EF 6 using a code-first approach.
Let's take simple and classical example. I have two entities Invoice and UserApplication which have a one-to-many relationship:
I also want to have an UpdatedById relationship with the same ApplicationUser table, to be able to show the names in the UI of who added the record and who modified it.
public partial class ApplicationUser : IdentityUser
{
public string FirstName { get; set; };
public string LastName { get; set; };
}
public virtual List<Invoice> Invoices { get; set; }
public class Invoice
{
public int Id { get; set; }
public string Details { get; set; }
public string CreatedById { get; set; }
public string UpdatedById { get; set; }
}
public virtual ApplicationUser CreatedBy { get; set; }
builder.Entity<Invoice>()
.HasOne(f => f.CreatedBy)
.WithMany(mu => mu.Invoices)
.HasForeignKey(f => f.CreatedById);
If you want Navigation Properties on Application user for these relationships, you would need to create and configure seperate ones.
eg
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System;
using System.Collections.Generic;
namespace EfCore6Test
{
public partial class ApplicationUser //: IdentityUser
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<Invoice> InvoicesCreated { get; } = new HashSet<Invoice>();
public virtual ICollection<Invoice> InvoicesLastUpdated { get; } = new HashSet<Invoice>();
}
public class Invoice
{
public int Id { get; set; }
public string Details { get; set; }
public int CreatedById { get; set; }
public int UpdatedById { get; set; }
public virtual ApplicationUser CreatedBy { get; set; }
public virtual ApplicationUser LastUpdatdBy { get; set; }
}
public class Db: DbContext
{
public DbSet<Invoice> Invoices{ get; set; }
public DbSet<ApplicationUser> Users{ get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Invoice>()
.HasOne(f => f.CreatedBy)
.WithMany(mu => mu.InvoicesCreated)
.HasForeignKey(f => f.CreatedById)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Invoice>()
.HasOne(f => f.LastUpdatdBy)
.WithMany(mu => mu.InvoicesLastUpdated)
.HasForeignKey(f => f.UpdatedById)
.OnDelete(DeleteBehavior.Restrict);
base.OnModelCreating(modelBuilder);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=localhost;database=efCore6Test;Integrated Security=true;TrustServerCertificate=true", o => o.UseRelationalNulls(true))
.LogTo(Console.WriteLine, Microsoft.Extensions.Logging.LogLevel.Information);
base.OnConfiguring(optionsBuilder);
}
}
class Program
{
static void Main(string[] args)
{
{
using var db = new Db();
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
}
}
}
}
Or simply omit the Navigation Properties on Application User.

EF Core Relationship mapping

In project I can have one User that can have many UserActivites. In my models I've set up their relationship as follows:
public class User
{
public int Id { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
//relationship mapping example
// delete these attributes and you'll cause a self referenceing loop error
[JsonIgnore]
[IgnoreDataMember]
public List<UserActivity> Activities { get; set; }
}
public class UserActivity
{
public int Id { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Project { get; set; }
public DateTime EntryDate { get; set; }
// relationship mapping
public User User { get; set; }
}
And in my repository class, I'm getting all my user activities this way:
public async Task<IEnumerable<UserActivity>> GetAll()
{
var result = await _context.UserActivities.Include(activity => activity.User).OrderByDescending(x => x.EntryDate).ToListAsync();
return result;
}
However, when I run my project, the User property of UserActivities is null. So I checked the Microsoft docs on EF Core relationships and updated my OnModelCreating method inside of my context to also do the mapping as follows:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserActivity>().ToTable("UserActivities").Property(x => x.Id).ValueGeneratedOnAdd();
modelBuilder.Entity<UserActivity>().ToTable("UserActivities").HasOne(x => x.User).WithMany();
modelBuilder.Entity<User>().ToTable("Users").Property(x => x.Id).ValueGeneratedOnAdd();
base.OnModelCreating(modelBuilder);
}
However, when I run the project again, my User property still isn't populated. I know this isn't a data issue as I have data inside of my User table and display that on a separate page.
I'm not sure what I'm doing wrong/missing with this. So any help would be appreciated
Try this code:
Your tables:
public partial class User
{
public User()
{
UserActivities = new HashSet<UserActivity>();
}
[Key]
public int Id { get; set; }
[Required]
public string UserName { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public string Email { get; set; }
[InverseProperty(nameof(UserActivity.User))]
public virtual ICollection<UserActivity> UserActivities { get; set; }
}
public partial class UserActivity
{
[Key]
public int Id { get; set; }
public int UserId { get; set; }
public string Project { get; set; }
public DateTime EntryDate { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("UserActivity")]
public virtual User User { get; set; }
}
dbcontext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserActivity>(entity =>
{
entity.HasOne(d => d.User)
.WithMany(p => p.UserActivities)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_UserActivity_User");
});
OnModelCreatingPartial(modelBuilder);
}

Data property inheritance in EF Core 3.0

I have a problem with the realization of data hierarchy in EF Core 3.0 (I need to use TPH).
Let's look:
public abstract class User
{
public Guid Id { get; set; }
public string Name { get; set; }
public abstract UserProfile **Profile** { get; set; }
}
public class ConcreteUser1 : User
{
public string ConcreteUser1Prop { get; set; }
public override UserProfile Profile { get; set; }
}
public class ConcreteUser2 : User
{
public string ConcreteUser2Prop { get; set; }
public override UserProfile Profile { get; set; }
}
And here we have Profile classes:
public class UserProfile
{
public Guid Id { get; set; }
public string SameProp { get; set; }
public Guid UserId { get; set; }
public User User { get; set; }
}
public class ConcreteUser1Profile : Profile
{
public string ConcreteProfile1Prop { get; set; }
}
public class ConcreteUser2Profile : Profile
{
public string ConcreteProfile2Prop { get; set; }
}
Let it be only one DbSet<User> which can be used for getting data from Database.
So, I can't understand, how to say EF Core (3.0) 2 things: how to say to store ConcreteUser*Profile (possible, Add and SaveChanges will work properly and write concrete profile type when I add concrete type user with concrete profile type. But I don't know how to say EF Core to get the correct concrete profile type when I use Where or FirstOrDefault method?
Is this model correct in principle?
Upd.
For example, I have 2 records in my Db: ConcreteUser1 user1, ConcreteUser2 user2. So, let's have DbSet<User> Users, so, what will I have after the request: var tstUser = ExampleDbContext.Users.FirstOrDefault();? What will the type of Profile variable in tstUser.Profile?
You can use HasDiscriminator on model creating.
It will use a field to be able to decide which concrete user class you're trying map the data to.
For you it'll be something like:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasDiscriminator<int>("UserType")
.HasValue<ConcreteUser1>(1)
.HasValue<ConcreteUser2>(2);
}
More at:
https://www.learnentityframeworkcore.com/configuration/fluent-api/hasdiscriminator-method
I have a solution (maybe someone will use it too).
public class UserProfile
{
public Guid Id { get; set; }
public ProfileRoles Role { get; set;}
public string SameProp { get; set; }
public Guid UserId { get; set; }
public User User { get; set; }
}
public class ConcreteUser1Profile : UserProfile
{
public string ConcreteProfile1Prop { get; set; }
}
public class ConcreteUser2Profile : UserProfile
{
public string ConcreteProfile2Prop { get; set; }
}
and
public class User
{
public Guid Id { get; set; }
public string Name { get; set; }
public UserRoles Role { get; set; }
public UserProfile Profile { get; set; }
}
public class ConcreteUser1 : User
{
public string ConcreteUser1Prop { get; set; }
}
public class ConcreteUser2 : User
{
public string ConcreteUser2Prop { get; set; }
}
public enum UserRoles
{
User = 0,
ConcreteUser1 = 1,
ConcreteUser2 = 2
}
public enum ProfileRoles
{
BaseProfile = 0,
ConcreteProfile1 = 1,
ConcreteProfile2 = 2
}
And It needs to be configured well in the DbContext:
public class UserStoreDbContext : DbContext
{
DbSet<User> Users { get; set; }
DbSet<UserProfile> Profiles { get; set; }
public UserStoreDbContext(DbContextOptions<UserStoreDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>(builder =>
{
builder.HasDiscriminator<UserRoles>(x => x.Role)
.HasValue<User>(Roles.User)
.HasValue<Logistian>(Roles.ConcreteUser1)
.HasValue<Driver>(Roles.ConcreteUser2)
});
modelBuilder.Entity<UserProfile>(builder =>
{
builder.HasDiscriminator<ProfileRoles>(x => x.Role)
.HasValue<UserProfile>(ProfileRoles.BaseProfile)
.HasValue<ConcreteUser1Profile>(Roles.ConcreteProfile1)
.HasValue<ConcreteUser2Profile>(Roles.ConcreteProfile2)
});
}
}
In this case when you will use the code like: dbContext.Users.FirstOrDefault(), you also will get correct derived profile from UserProfile.
Maybe someone will need this solution too.

EF self one-to-many relationship

I want to implement one-to-many relationship with EF6. Table User can handle many Friends, i can implement that with map table:
--TABLE USERS:
Id
--TABLE USER_MAP:
UserOwnerId
UserFriendId
But how to implement that with EF6?
Here is my entity User:
public class User
{
...
public virtual List<User> Friends { get; set; }
...
}
You can use something like this
// Relationships
HasRequired(t => t.User)
.WithMany(t => t.Friends)
.HasForeignKey(d => d.UserId);
https://msdn.microsoft.com/en-us/data/hh134698.aspx
One-to-Many relationship using DataAnnotations:
public class User
{
public User() { }
public int UserId { get; set; }
public string Name { get; set; }
public virtual Friends friends { get; set; }
}
public class Friends
{
public Friends()
{
Users = new List<User>();
}
public int FriendId { get; set; }
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
you can defined in Code first like that:
1) Fluent API:
public class Student
{
public Student() { }
public int StudentId { get; set; }
public string StudentName { get; set; }
public virtual Standard Standard { get; set; }
}
public class Standard
{
public Standard()
{
Students = new List<Student>();
}
public int StandardId { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
Fleut Api:
in your DbContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//one-to-many
modelBuilder.Entity<Student>()
.HasRequired<Standard>(s => s.Standard)
.WithMany(s => s.Students);
}
virtual keyword is only for Lazy loading you can remove it if you do not need it
2) Code first:
public class Student
{
public Student()
{
Students= new List<Student>();
}
public int StundendId{ get; set; }
public string StudentName { get; set; }
public int? SharedStudentId{ get; set; }
[ForeignKey("SharedStudentId")]
public Student SharedStudent{ get; set; }
public virtual ICollection<Student> SharedStudents{ get; set; }
}

Error -"Could not drop constraint" when execute .AsQueryable();

I am using EF code first to generate many to many relation. as the following:
public class User
{
public User()
{
Categories = new Collection<Category>();
}
public int UserId { get; set; }
public string LastName { get; set; }
public ICollection<Category> Categories { get; set; }
}
and
public sealed class Category
{
public Category()
{
Users = new Collection<User>();
}
public string Name { get; set; }
public int Id { get; set; }
public ICollection<User> Users { get; set; }
}
My Db context look like:
public DbSet<User> Users { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasMany(b => b.Categories).WithMany(a => a.Users).Map(m => m.MapLeftKey("userId").MapRightKey("id"));
base.OnModelCreating(modelBuilder);
}
The weird issue is when Im doing simple action like:
_ctx.Categories.AsQueryable();
I get the following error:
The constraint 'PK_dbo.Categories' is being referenced by table 'UserCategories', foreign key constraint 'FK_dbo.CategoryUsers_dbo.Categories_id'.
Could not drop constraint. See previous errors.

Categories