One to many with applicationuser - asp.net-mvc

If this is a dupp, by all means direct me to the answer.
ASP.NET, MVC5, EF6
Each application user can have many TfsAccountCredentials
IdentityModel.cs has the following:
public class ApplicationUser : IdentityUser
{
public virtual ICollection<TfsAccountCredentials> TfsAccountCredentials { get; set; }
}
TfsAccountCredentials.cs has the following:
public class TfsAccountCredentials
{
public int Id { get; set; }
//other properties
[ForeignKey("ApplicationUserId")]
public virtual ApplicationUser ApplicationUser { get; set; }
public string ApplicationUserId { get; set; }
}
TfsAccountCredentialsDb has the following:
public class TfsAccountCredentialsDb : DbContext
{
public TfsAccountCredentialsDb() : base("DefaultConnection")
{
}
public DbSet<TfsAccountCredentials> TfsAccountCredentials { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<TfsAccountCredentials>()
.HasRequired(ac => ac.ApplicationUser)
.WithMany(ac => ac.TfsAccountCredentials)
.HasForeignKey(ac => ac.ApplicationUserId);
}
}
IdentityDb.cs has the following:
public class IdentityDb : IdentityDbContext<ApplicationUser>
{
public IdentityDb() : base("DefaultConnection")
{
}
}
Two things. First, when I add a migration using the Identity context, part of the script it generates adds the TfsAccountCredentials table, which already exists due to an earlier migration for the TfsAccountCredentials context.
Second, when I add a migration using the TfsAccountCredentials context, I get the following error:
TfsTeamStatus.Web.DataContexts.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
TfsTeamStatus.Web.DataContexts.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType.
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type 'IdentityUserLogin' that has no keys defined.
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined.
EDIT
My final solution:
IdentityModel.cs contains the following:
public class ApplicationUser : IdentityUser
{
public virtual ICollection<TfsAccountCredentials> TfsAccountCredentials { get; set; }
}
TfsAccountCredentials.cs contains the following:
public class TfsAccountCredentials
{
public int Id { get; set; }
//other properties
[ForeignKey("ApplicationUserId")]
public virtual ApplicationUser ApplicationUser { get; set; }
public string ApplicationUserId { get; set; }
}
ApplicationDb.cs contains the following:
public class ApplicationDb : IdentityDbContext<ApplicationUser>
{
public ApplicationDb() : base("DefaultConnection")
{
}
public DbSet<TfsAccountCredentials> TfsAccountCredentials { get; set; }
}
So TfsAccountCredentialsDb.cs and IdentityDb.cs got combined.

Why you are making to separate DB? I think you want make 2 table in same DB not different DB so remove your TfsAccountCredentialsDb and add your TfsAccountCredentials to IdentityDb:
public class IdentityDb : IdentityDbContext<ApplicationUser>
{
public IdentityDb() : base("DefaultConnection")
{
}
public DbSet<TfsAccountCredentials> TfsAccountCredentials { get; set; }
}

You don't need IdentityDb because IdentityDbContext<ApplicationUser> is the context that handles Identity issues. So then you can either:
A) Have TfsAccountCredentialsDb inherit from IdentityDbContext<ApplicationUser>. This will allow you to reference ApplicationUser in your models. The DbSet for ApplicationUser is in the base class you can't see.
B) If you want TfsAccountCredentialsDb to inherit from DbContext, then you will have to add a copy of ApplicationUser in that context along with it's DbSet that you can use to reference within your app's context.

Related

Issue adding migration involving entity that reference ApplicationUser in ASP.NET MVC 5 with Entity Framework code-first

ASP.NET MVC 5, I am having some issues with adding migration when involving entities that are referencing the ApplicationUser entity. I am using individual account for authentication when created the project.
public class Blog
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[ForeignKey("ApplicationUser")]
public string ApplicationUserId { get; set; }
public ApplicationUser ApplicationUser { get; set; }
[Required]
[StringLength(500, ErrorMessage = "The {0} must be at least {2} characters long.")]
public string Content { get; set; }
}
public class ApplicationUser : IdentityUser
{
public bool IsSoftDeleted { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
}
And my DBContexts is
public class ApplicationUserDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationUserDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationUserDbContext Create()
{
return new ApplicationUserDbContext();
}
}
public class BloggingServiceDbContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public BloggingServiceDbContext() : base("DefaultConnection")
{
}
}
The script I have run on package management console is:
Add-Migration InitialBlogMigration -ConfigurationTypeName BloggerConfiguration
The error I get is:
BloggingService.Web.Context.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
BloggingService.Web.Context.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType.
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type 'IdentityUserLogin' that has no keys defined.
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined.
Note: before implemented Blog, there was no issue with running add-migration and the database do not contain any of the entities mentioned in the error message.
I have run out of clues on what could be the issue. Can you please help me spot the issue?
The resolution seems to be simple, I need to place all entities where referencing ApplicationUser to the ApplicationUserDbContext. But I still don't know why this is the case, would be nice if someone could clarify this for me.

Multiple DbContext in ASP MVC: Possible to avoid IdentityDbContext inheritance?

I'm using EntityFramework 6. I would like to split my DbContext into multiple smaller ones. Edit: I have a single database I wish to connect to.
I will have a single DbContext with all the entities and migrations that only one central application will use. Other applications will use the smaller DbContext without migrations.
I have found that I need to inherit all DbContext from IdentityDbContext, even if they use none of it.
internal class SmallerDbContext : IdentityDbContext<ApplicationUser,
ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public DbContext<Entity1> NotInSmallerDbContext { get; set; }
public DbContext<Entity1> InSmallerDbContext { get; set; }
}
I would like this to be:
internal class SmallerDbContext : System.Data.Entity.DbContext
{
public DbContext<Entity1> InSmallerDbContext { get; set; }
}
But this yields the following errors:
Paris.DAL.Repo.DbContext.ApplicationUserLogin: : EntityType 'ApplicationUserLogin' has no key defined. Define the key for this EntityType.
Paris.DAL.Repo.DbContext.ApplicationUserRole: : EntityType 'ApplicationUserRole' has no key defined. Define the key for this EntityType.
ApplicationUserLogins: EntityType: EntitySet 'ApplicationUserLogins' is based on type 'ApplicationUserLogin' that has no keys defined.
ApplicationUserRoles: EntityType: EntitySet 'ApplicationUserRoles' is based on type 'ApplicationUserRole' that has no keys defined.
I have tried to add these tables to the DbContext, but to no avail.
public IDbSet<ApplicationUser> Users { get; set; }
public IDbSet<ApplicationRole> Roles { get; set; }
Is there any way I can create DbContext that does not inherit from IdentityDbContext?
I was on the right path by adding the objects to the DbContext.
You need to add only two, the User and UserLogin. The others are not needed.
public DbSet<ApplicationUser> Users { get; set; }
public DbSet<ApplicationUserLogin> UserLogins { get; set; }
Additionally, you need to set the correct table for both objects and you need to add some of virtual properties so that Entity Framework can handle these types as it would any of your other classes.
[Table("AspNetUsers")]
public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
}
[Table("AspNetUserLogins")]
public class ApplicationUserLogin : IdentityUserLogin<int>
{
[Key, Column(Order = 0)]
public override string LoginProvider { get; set; }
[Key, Column(Order = 1)]
public override string ProviderKey { get; set; }
[Key, Column(Order = 2)]
public override int UserId { get; set; }
}
Now, your DbContext no longer has to inherit from IdentityDbContext.

Assigning a role to a user in extended Asp.Net Identity 2 error Violation of PRIMARY KEY constraint 'PK_dbo.AspNetUserRoles'

I have extended AspNetUserRoles for my application where I have added a new FK column ApplicationId in AspNetUserRoles table. The idea behind this is to allow same user to be in different applications with same or different roles.
Everything seems Ok till I tried to add the same role to the same user but for a different application where I have started getting the error:
Violation of PRIMARY KEY constraint 'PK_dbo.AspNetUserRoles'. Cannot
insert duplicate key in object 'dbo.AspNetUserRoles'.
Could please anyone help me to come out of this problem.
my IdenitityModels is as follow
public class ApplicationUser : IdentityUser
{
public virtual AspNetApplications AspNetApplication { get; set; }
public virtual AspNetUserRoles AspNetUserRoles { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
public DbSet<AspNetApplications> AspNetApplications { get; set; }
public DbSet<AspNetUserRoles> AspNetUserRoles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
My AspNetApplications and AspNetUserRoles models are as follow
public class AspNetApplications
{
[Key]
public string ApplicationId { get; set; }
public string ApplicationName { get; set; }
}
public class AspNetUserRoles : IdentityUserRole
{
[Key]
public string ApplicationId { get; set; }
[ForeignKey("ApplicationId")]
public AspNetApplications AspNetApplications { get; set; }
}
Following is the code where I am adding a new entity of type AspNetUserRoles and it throws the error at dbContext.SaveChanges()
var aspNetUserRole = new AspNetUserRoles
{
UserId = userId,
RoleId = roleId,
ApplicationId = applicationId,
};
dbContext.AspNetUserRoles.Add(aspNetUserRole);
dbContext.SaveChanges();
IdentityUserRole implements a composite foreign key consistent of UserId and RoleId. Your subclass only has a key set for ApplicationId, so one of two things is happening:
The key is ApplicationId, in which case only one user role could ever be added for any given application.
The key is UserId and RoleId, and since it's the same user and same role, you're violating the constraint.
Essentially, you need to ensure that the composite key consists of UserId, RoleId, and ApplicationId. Since you can't control the base implementation of IdentityUserRole, the best way to ensure that would be to use fluent config. Add the following to your context class.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<AspNetUserRoles>().HasKey(m => new { m.ApplicationId, m.UserId, m.RoleId });
}
Also, FWIW, you don't need to name your classes AspNet*. If you want the same table names, just decorate the class with [Table("AspNetUserRoles")].

EF6 I have GUID for UserId Stored in a table but want to add ApplicationUser to the Model

My Application is all fine and within IdentityModels I set each class (table). But I want to show in my Razor View the UserName from AspNetUsers and not the GUID. I currently store the GUID but thats all i'm able to display in the views
I'm thinking there must be a built in easy way to do this - and that I don't need to do any mapping or do i
I'm using EF6 and MVC4.5
Here is my class :
public partial class x23BatchImport
{
public int x23BatchImportId { get; set; }
public Nullable<DateTime> DateTimeFromFilename { get; set; }
public string UserId { get; set; }
public string Filename { get; set; }
public decimal? Length { get; set; }
public Nullable<DateTime> StartDateTime { get; set; }
public Nullable<DateTime> StopDateTime { get; set; }
//public virtual ApplicationUser ApplicationUser { get; set; }
}
...here is an extract from IdentityModels.cs
namespace AscendancyCF.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
//public System.Data.Entity.DbSet<AscendancyCF.Models.ApplicationUser> ApplicationUser { get; set; }
public System.Data.Entity.DbSet<AscendancyCF.Models.SupplyPointType> SupplyPointTypes { get; set; } ETC ETC
.....NB all my tables are declared here then I use OnModelCreating to set up relationships some of the time...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Reference : http://blogs.msdn.com/b/adonet/archive/2010/12/06/ef-feature-ctp5-fluent-api-samples.aspx
base.OnModelCreating(modelBuilder);
// Configure the 1-1
modelBuilder.Entity<SupplyPoint>()
.HasOptional(a => a.SupplyPointAddress)
.WithMany()
.HasForeignKey(u => u.SupplyPointAddressId);
}
Entity Framework has a set of model and property naming conventions that it uses by default. Currently, it's not able to figure out that UserId is a foreign key to an ApplicationUser.
If you don't want to add any manual mappings, you have to change your naming. The simplest would be to rename the ApplicationUser property to User.
public virtual ApplicationUser User { get; set; }
When doing your queries, use Include() to eager load the User property with the matching ApplicationUser...
// using System.Data.Entity; // add this using to use Include()
var context = new ApplicationDbContext();
var batchImport = context.x23BatchImport
.Include(x => x.User)
.(x => x.x23BatchImportId == 1)
.Single();
var username = batchImport.User.UserName;
Your other alternatives are:
Change UserID property to ApplicationUserId
Specify the foreign key in a manual mapping in OnModelCreating()
Specify the foreign key on the model using data annotations

MVC No Key Defined

I am getting this error in my MVC Application:
One or more validation errors were detected during model generation:
System.Data.Edm.EdmEntityType: : EntityType 'CustomerModel' has no key defined. Define the key for this EntityType.
System.Data.Edm.EdmEntitySet: EntityType: EntitySet �Customer� is based on type �CustomerModel� that has no keys defined.
My Customer Model looks like this:
public class CustomerModel
{
public string Name { get; set; }
public int CustomerID { get; set; }
public string Address { get; set; }
}
public class CustomerContext : DbContext
{
public DbSet<CustomerModel> Customer { get; set; }
}
By default, Entity Framework assumes a key property called Id exists in your model class. Your key property is called CustomerID, so Entity Framework can't find it.
Either change the name of your key property from CustomerID to Id, or decorate the CustomerID property with the Key attribute:
public class CustomerModel
{
public string Name { get; set; }
[Key]
public int CustomerID { get; set; }
public string Address { get; set; }
}
public class CustomerContext : DbContext
{
public DbSet<CustomerModel> Customer { get; set; }
}

Resources