Reputation: 21
would really appreciate a bit of guidance on how to use ApplicationUser within my own custom class in MVC5.
Simple model, using scaffolding to create controller and view, sm DbContext for the default ApplicationUser (IdentityUser) from the Internet Application template. I want to use the ApplicationUser to stamp the transaction with the details of whoever was logged in at the time.
I get one of two database errors when Entity Framework tries to DropAndRecreateAlways
First my class:
public class Example
{
public int ID { get; set; }
[Required]
public string Description { get; set; }
[Required]
public double Amount { get; set; }
[Required]
public virtual ApplicationUser CreatedBy {get; set;}
[Required]
public virtual ApplicationUser ModifiedBy { get; set; }
}
Errors I get when Entity Framework tries to create the database are:
{"One or more validation errors were detected during model generation:\r\n\r\nMvcApplication1.Models.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.\r\nMvcApplication1.Models.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType.\r\nIdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type 'IdentityUserLogin' that has no keys defined.\r\nIdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined.\r\n"}
A referential integrity due to Cascade on Delete (I can override DbContext to remove cascading deletes)
What is the best way to achieve this? Any guidance would be appreciated.
Upvotes: 2
Views: 2321
Reputation: 21
I've decided to post an answer that works, however I remain unconvinced it's the cleanest answer and would love to hear if anyone has a better way of doing this.
The answer for me to get this to work was to override OnModelCreating()
in ApplicationDbContext: IdentityDbContext
and use Fluent API to mark properties of IdentityUserLogin
and IdentityUserRole
as [Key]
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Entity<IdentityUserLogin>().HasKey(t => t.UserId);
modelBuilder.Entity<IdentityUserRole>().HasKey(t => t.UserId);
}
I don't think this is a very good solution as EF Code First now creates two columns in my IdentityUserLogin
and IdentityUserRole
tables, UserId
and User_Id
.
This will do for now. Suggestions are VERY welcome.
Upvotes: 0
Reputation: 656
Your problem is that your forgot to call
base.OnModelCreating(modelBuilder);
On top off your method since like you said ApplicationDbContext is created by default inheriting from IdentityDbContext. So calling base.OnModelCreating, let you base class ie IdentityDbContext, generate all you need.
But if you still want to use fluent API, the correct way for creating the key for that two entities would be
modelBuilder.Entity<IdentityUserLogin>().HasKey(t => new { t.UserId, t.ProviderKey, t.LoginProvider });
modelBuilder.Entity<IdentityUserRole>().HasKey(t => new { t.RoleId, t.UserId });
Without doing that, calling AddToRole(userid, rolename) method of UserManager will throw an exception requiring the extra key you added with the message "The field UserId or RoleId is required".
Upvotes: 2
Reputation: 8674
I'd suggest you to annotate your ID
with [Key]
attribute.
Currently EF can't find the primary key for table Example
based upon the first error you've posted.
Also, if you want to lazy load CreatedBy
and ModifiedBy
in future, you also need to mention Id
for that, even though that is not an error for now. It might be easy for future.
Apart from that, also inherit your ApplicationUser
class from IdentityUser
class and DbContext
class from IdentityDbContext
class.
Clean the project, rebuild it and see if any error occurs. Then it might be easier to solve it.
Upvotes: 1
Reputation: 539
Two suggestions:
1 - Make sure that your dbcontext derives from IdentityDbContext.
2 - Based on your model, you have relationships between the user and your other entities. How does your dbcontext DBSet statements look? Do you have a dbset for your users? (which means you are assuming management of users instead of the IdentityFramework). If you don't have a DBSet for your users, then I would agree with Ashish's statement, the context of Identity entities might be different from the context of your other entities, which will create problems.
If you can post the basics of your context class, we might be able to tell more
Upvotes: 0
Reputation: 2764
It is looking for the [Key]
annotation for your entities. Looks like you are missing one for both IdentityUserLogin
and IdentityUserRole
public class Person
{
[Key] // <--- this needs to be identified here or in the DbContext you setup
public Guid ID { get; set; }
}
Upvotes: 0