I cannot reproduce the issue, even when I create the tables in another database without keys and relations. So I'm sure that there is a problem with your model. Unfortunately you didn't add code which I can compare, so I can't tell what is different and answer the question directly. The only thing I can do is to show what works for me. However, first I have some remarks.
I think you shouldn't follow the article. As there is no reason to add the context to an existing database.
Like Ivan Stoev mentioned you are not supposed to mix contexts. The Identity context is meant to authenticate the user. It stores the credentials, the roles of the user and claims. Where claims are meant to add identity information about the user.
In fact, the default Hometown
field of the ApplicationUser template can be removed, as it is an identity claim which should be stored in the AspNetUserClaims table. Not something you need to extend the ApplicationUser for. Actually I can't think of any reason to extend the ApplicationUser.
About the roles, these are not really claims, as they tell nothing about the identity but rather are used for authorization. That's why it's fine that they are stored in the AspNetUserRoles table. Unfortunately roles are added to the identity as role claims, which makes things confusing.
Please note that the Identity information is present in the claims. This means that the application doesn't have to call the Identity context. E.g. User.IsInRole checks the role claims of the current identity, not the roles stored in the table.
About the different contexts, the other context (which I usually call the business model) has nothing in common with the Identity context. Email and other fields are not part, nor have meaning to the business model. You may think that those fields are redundant, but in fact they are not. I could login using a google account, but for the business use my work email address.
There are several reasons to keep the context seperated.
- Seperation of concerns. Suppose you want to exchange the authentication framework in the future with another one. Like implement IdentityServer in case you want to support single sign-on (SSO).
- You can't move the users table to another database if another application needs the same logins. So you'll end up adding other contexts as well to the database.
- Trouble with migrations. If you mix the contexts then migrations will fail.
- It'll makes things far more easier. This is the first problem you've encountered, not the last.
As also mentioned in the article:
At this point if you need to add any relationships (E.g. foreign keys)
from your own tables to these tables you are welcome to do so but do
not modify any of the Entity Framework 2.0 tables directly or later on
any of their POCO classes. Doing so will result in errors based upon
feedback I’ve received.
So how to manage the information if you shouldn't access the identity context from your application?
For the current user you don't need to access the users table. All the information is present in the identity claims. The only reason to access the identity context is to allow a user to login. Besides user management.
You can suffice by adding a reference to the user (the userid). If you need to show information of other users (like name) in a report, then create a user table in your business context to store the information. You can add relations to this table, as it is part of the same context.
Please let me know if you have questions about this approach.
Now the code that works for me. Like others have mentioned, it is not likely that adding the line:
public ICollection<Employee> Employees { get; set; }
is the cause. Without the virtual
keyword I think it is even ignored (remains null).
When I follow the steps of the article then I end up with the following model:
public class ApplicationUser : IdentityUser
{
public string Hometown { get; set; }
//public virtual ICollection<Employee> Employees { get; set; }
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("DefaultConnection", throwIfV1Schema: false)
{
// Disable migrations
//Database.SetInitializer<ApplicationDbContext>(null);
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
And then I add the Employee class and uncomment the line in the ApplicationUser class above:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
//public virtual ApplicationUser ApplicationUser { get; set; }
public string ApplicationUserId { get; set; }
}
In the database I added the table:
CREATE TABLE [dbo].[Employees](
[Id] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
[ApplicationUserId] [nvarchar](128) NOT NULL,
PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
You can use the [ForeignKey]
attribute to use a different field name.
You can try this or choose to keep both contexts seperated instead.
AspNetUserLogins
table probably has no primary key or just attached to wrong context. Can you showAspNetUserLogins
class structure? – OuselICollection<Employee>
property. And, this only happens when I add complex-type properties. I don't get an error message when I addstring FirstName
, for example. – Shoshonepublic ICollection<Employee> { get; set; }
has no name, I doubt this compiles. Are we speaking about an entity? Why does it have aGenerateUserIdentityAsync
? – SesquiplaneGenerateUserIdentityAsync
? – ShoshoneAspNetUserLogins
andctx.SaveChanges()
? – SesquiplaneAspNetUserLogins
record via EntityFramework? Without the property you have had a new record in your database table? Then the error message is a bug and should be reported. When does the error throw? – SesquiplaneICollection<Employee>
property. – Shoshone