Code first migration - sub-class requires Id field - entity-framework

I have a standard MVC 5 project in VS 2013 and using the built-in Identity provider. I am trying to customize the user profile according to http://blogs.msdn.com/b/webdev/archive/2013/10/16/customizing-profile-information-in-asp-net-identity-in-vs-2013-templates.aspx.
I did not expand on ApplicationUser as in the article as I wanted to work on the extension in another project in the same solution. I created a new sub-class ExtendedUser:
public class ExtendedUser : IdentityUser
{
[MaxLength(12)]
public string PIN { get; set; }
}
I then have:
public class UsersContext : DbContext
{
public DbSet<ExtendedUser> ExtendedUsers { get; set; }
public UsersContext() : base() { }
public UsersContext(string ConnectionString) : base(ConnectionString) { }
}
When UsersContext is instantiated and initialized, I get hit by:
System.Data.Entity.ModelConfiguration.ModelValidationException was unhandled by user code
HResult=-2146233088
Message=One or more validation errors were detected during model generation:
IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
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.
....
It seems like the other Identity membership tables are updated, but I did not touch any of those. Why is this happening and how do I correct it.

Try IdentityDbContext<ExtendedUser> as your base class for UsersContext as it is in the post you have mentioned. Without it you don't have any line of code to tell ef which property is the key. If you don't want IdentityDbContext you should in method void OnModelCreating(DbModelBuilder modelBuilder) put property mapping, something like:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ExtendedUser>().HasKey(t => t.Id);
...
}

Related

EntityType 'IdentityUserLogin' has no key defined. After trying to set up Foreign Key

I am using entity framework code-first design.
For my application a customer should have a creator which is an user from AspNetUser.
Customer Class
public class Customer
{
public string CreatorId { get; set; }
[ForeignKey("CreatorId")]
public ApplicationUser Creator { get; set; }
}
IdentityModel
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("AgueroCRMDbContext", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
After I build I can still register/login but I get this error when trying to access Customers
AgueroCRM.Data.Service.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
AgueroCRM.Data.Service.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.
Line 38: public IEnumerable<Customer> GetAll()
Line 39: {
Line 40: return from r in db.Customer <-- error occurs here
Line 41: orderby r.Id
Line 42: select r;
Everything was working until I decided to add this foreign key.
Edit: I think this might have something to do with not able to access the IdentityDbContext that contain ApplicationUser from the DbContext that contain Customers.
Anyone know how to solve this?
Solved: by merging my ApplicationDbContext into my Main DbContext
public class AgueroCRMDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<Customer> Customer { get; set; }
public AgueroCRMDbContext()
: base("AgueroCRMDbContext", throwIfV1Schema: false)
{
}
public static AgueroCRMDbContext Create()
{
return new AgueroCRMDbContext();
}
}
How is you Startup class? Yesterday i faced to same issue, i forget call services.AddIdentity(). You called this method on you Startup class?
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<YourIdentityDbContext>(
options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>(
options =>
{
options.SignIn.RequireConfirmedAccount = false;
options.Password.RequireUppercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireDigit = false;
}).AddEntityFrameworkStores<UnaIdentityDbContext>();
services.AddAuthentication();
services.AddAuthorization();
}

How to I create an Entity Framework ObjectSet using a generic type?

I am connecting to a database-first dll using Entity Framework 6.2.0 and I am trying to get the primary key for a given Entity at runtime. I don't know the Entity type until runtime, which is why I'm trying to use reflection to get the primary key.
Using the following, I'm getting the error Mapping and metadata information could not be found for EntityType 'System.Type':
private string GetPrimaryKey<T>(T entity) where T : class
{
Context.DefaultContainerName = EFContainerName;
var ESet = Context.CreateObjectSet<T>().EntitySet;
return ESet.ElementType.KeyMembers.Select(k => k.Name).ToArray().First();
}
I've seen a lot of information on the Mapping and Metadata error, but not with System.Type and so I feel like it may be less of a mapping error and more the way I'm using the Generic Type parameter?
create abstract class like this
public abstract class EntityObject
{
public abstract Guid EntityKey { get; }
}
inherit this class from an entity object
public class Model: EntityObject
{
public Guid Id { get; set; }
public override Guid EntityKey => Id;
}
for use;
var primaryKey = (Model as EntityObject)?.EntityKey;

EF Migration Clear Cache

public class A
{
public int Id { get; set; }
public virtual ICollection<AHistory> AHistorys { get; set; }
}
public class AHistory
{
public int AId { get; set; }
public virtual A A {get; set; }
}
I renammed AHistories to AHistory.
add-migration HistoMig
AHistories: EntityType: EntitySet 'AHistories' is based on type 'AHistory' that has no keys defined.
So the error mention an old name that no longer exists in the solution.
What should I do ?
I've already clean Visual Studio Solution with no effects.
I also tried to comment out navigation property, add migration, rollback migration, uncomment then add migration ; I still get this erros.
I've done a search through VS solution on String "AHistories" with 0 occurence found.
Based on ESG comment, I've added :
public class DefaultContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new AHistoryMapping());
public DbSet<AHistory> AHistorys { get; set; }
}
}
public class AHistoryMapping : EntityTypeConfiguration<AHistory>
{
public AHistoryMapping()
{
HasKey(ah => ah.AId);
}
}
It works now !
Edit
Actually it doesn't "work"... It compiles but the result is not what I was expecting.
This code creates a table with a unique identifier named FundId and a foreign key named Fund_Id.
I've change my code to
public class AHistoryMapping : EntityTypeConfiguration<AHistory>
{
public AHistoryMapping()
{
HasRequired(ah => ah.A)
.WithMany(a => a.AHistorys)
.HasForeignKey(ah => ah.AId);
}
}
It doesn't compile anymore. I get the message again.
AHistory: : EntityType 'AHistory' has no key defined. Define the key for this EntityType.
AHistorys: EntityType: EntitySet 'AHistorys' is based on type 'AHistory' that has no keys defined.
Edit 2
It turns out that EF require a Primary Key. Here is the solution :
public class AHistoryMapping : EntityTypeConfiguration<AHistory>
{
public AHistoryMapping()
{
HasKey(ah => new { ah.AId, Ah.Date });
HasRequired(ah => ah.A)
.WithMany(a => a.AHistorys)
.HasForeignKey(ah => ah.AId);
}
}

Can I have an self referencing inverse navigation property with optional foreign key?

ASP.NET Identity developers should recognize my renamed ApplicationUser class (now called User) derived from IdentityUser which has a Guid-based Id property. In my User class I have an optional self referencing foreign key (public Guid? ManagerId) and one simple matching navigation property (public User Manager). All that works. My problem is I want a second navigation property (DirectlyManagedUsers) and I can't figure out how to annotate it such that it will contain a collection of this User's directly managed users. I'd appreciate some help.
Here is my User class:
public class User : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<User> manager, string authenticationType)
{
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
return userIdentity;
}
public User() : base()
{
DirectlyManagedUsers = new List<User>();
}
public User(string userName) : base(userName)
{
DirectlyManagedUsers = new List<User>();
}
[ForeignKey(nameof(Manager))]
public Guid? ManagerId { get; set; }
[ForeignKey(nameof(ManagerId))]
public User Manager { get; set; }
[InverseProperty(nameof(Manager))]
public ICollection<User> DirectlyManagedUsers { get; set; }
}
I'm getting the following error on model generation:
One or more validation errors were detected during model generation:
User_DirectlyManagedUsers_Source_User_DirectlyManagedUsers_Target: : The types of all properties in the Dependent Role of a referential constraint must be the same as the corresponding property types in the Principal Role. The type of property 'ManagerId' on entity 'User' does not match the type of property 'Id' on entity 'User' in the referential constraint 'User_DirectlyManagedUsers'. The type of property 'ManagerId' on entity 'User' does not match the type of property 'Id' on entity 'User' in the referential constraint 'User_DirectlyManagedUsers'.
I know that has to do with the nullable Guid type of the ManagerId. So what do I do?
Okay, I figured out what was going wrong. I was using a nullable Guid (Guid?) as the type of my ManagerId. Actually in the ASP.NET Identity framework, the prebuilt Entity Framework IdentityUser class uses a string type for its Id property. This string property is set to the value of a new Guid converted to a string using .ToString(). Once I figured that out (and since I know that string is nullable) I simply changed the type of my ManagerId property to string and everything worked. So my problem was addressed by figuring out the right type in the Identity framework, not by annotating the property a different way for the Entity Framework. I am curious if anyone could answer the original question if the Id was not a nullable type.

Collection of IdentyUsers in EntityFramework - has no key defined

All works well till i decide to add IdentityUser collection in another entity as navigation property.
One or more validation errors were detected during model generation:
IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
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.
But they are part of Microsoft.AspNet.Identity.EntityFramework library. How is it that they has no keys defined???
My entities and db context (EF v6.1, AspNet.Identity v.2.0):
public class User : IdentityUser
{
public virtual int OrganizationId { get; set; }
public virtual Organization Organization { get; set; }
}
public class Organization
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class DatabaseModelContext : IdentityDbContext<User>
{
public DatabaseModelContext() : base("ConnectionString") { }
public DbSet<Organization> Organizations { get; set; }
}
Also tried to define explicit relations:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Organization>()
.HasMany(o => o.Users)
.WithOptional(u => u.Organization)
.HasForeignKey(u => u.OrganizationId);
modelBuilder.Entity<User>()
.HasOptional(u => u.Organization)
.WithMany()
.HasForeignKey(u => u.OrganizationId);
}
NO success!!!
It cant just be, that one must define key types for entity framework internal classes!!!
SOLUTION (update)
Actually my simplified example not reflecting my real app situation. My apologies.
I've been using multiple Dbcontexts in my app and organization entity come from separate context what derives form Dbcontext class. In that way this context know nothing about IdentityUser models but Organization entity involves User entity - there is a problem.
Solution - i derived all my other context from IdentityDbContext !!!
Actually my simplified example not reflecting my real app situation. My apologies. I've been using multiple Dbcontexts in my app and organization entity come from separate context what derives form Dbcontext class. In that way this context know nothing about IdentityUser models but Organization entity involves User entity - there is a problem.
Solution - i derived all my other context from IdentityDbContext !!!