Multiple object sets per type are not supported. The object sets 'ApplicationUsers' and 'Users' can both contain instances of type ApplicationUser - asp.net

I am stuck at an odd issue.
I am learning MVC 5 and almost everything is created by the built-in template.
I only added a class History
public class History
{
[Key]
public DateTime Date { get; set; }
public virtual ApplicationUser User { get; set; }
public string ItemName { get; set; }
}
And inside the built-in ApplicationUser:
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 virtual ICollection<History> Histories { get; set; }
}
Here is the error message:
Multiple object sets per type are not supported. The object sets 'ApplicationUsers' and 'Users' can both contain instances of type 'MyOnlineShopping.Models.ApplicationUser'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Multiple object sets per type are not supported. The object sets 'ApplicationUsers' and 'Users' can both contain instances of type 'MyOnlineShopping.Models.ApplicationUser'.
Source Error:
Line 124: {
Line 125: var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
Line 126: IdentityResult result = await UserManager.CreateAsync(user, model.Password);
Line 127: if (result.Succeeded)
Line 128: {
Source File: f:\Workplace\MyOnlineShopping\MyOnlineShopping\Controllers\AccountController.cs Line: 126

The above is just a work around, There are many answers to this same problem all around SO.
Here
Here
and Here
Look inside IdentityModel.cs, you will find
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
Inside of this context, VS sometimes adds DbSet<ApplicationUser> ApplicationUsers
THIS IS A DUPLICATE
Inside of the IdentityDbContext class is a DbSet User, when you subclass from IdentityContext, inheritance converts that line to DbSet<ApplicationUser> User.
The fix? Remove the DbSet<ApplicationUser> User from public class ApplicationDbContext : IdentityDbContext<ApplicationUser>

This error happens when your ApplicationDbContext class changed. just do this thing into your Models Folder and go to the IdentityModels.cs class and remove the Last line
public System.Data.Entity.DbSet < Project.Models.ApplicationUserProject.Models.ApplicationUser> ApplicationUsers { get; set; }
This line is generated automatically by scaffold.

I ended up renaming ApplicationUser to User, rescaffolding and everything magically started working.
Looks like the templates are a bit out of wack.

Related

ApplicationUser has a list of ApplicationUser

I have built a new Web Application that uses the template Visual Studio provides and included MVC and Web API. The default authorization mechanism is Identity and the database interaction is done using Entity Framework with Code-first method of creating the database.
I have three requirements:
A user can have a list of Children objects
I do not want to use a "relationship" object
All users already exist on the AspNetUsers table, because they all need to be able to login, so I do not want another table to maintain user data
In theory, multiple parents could have reference to multiple children, but for this example, we will just consider it a one-to-many relationship.
In my application, I need to have an ApplicationUser have a list of ChildUsers as a collection of ApplicationUser such as shown below.
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public string ShirtSize { get; set; }
public ICollection<ApplicationUser> Children { get; set; }
}
I want these users to be accessible as shown above (a collection of ApplicationUser), not a collection of Relationship object that ties them together such as:
public class Relationship
{
public String ParentId { get;set; }
public String ChildId { get;set; }
}
Can a new table be created and exist on the database without having a code-first model for it to know how to create a relationship table?
What are available solutions to this problem?
After some research, and experimentation, I have found bits and pieces of guidance to arrive at a solution that works.
In order for an intermediate table to be created to maintain the relationship, the ApplicationDbContext OnModelCreating function needs to know what it should look like. I have told it to create a new table that is not bound to an object by using the modelBuilder shown in the code below. Unfortunately, I do not have the links to the articles that guided me to this.
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base( "DefaultConnection", throwIfV1Schema: false )
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
base.OnModelCreating( modelBuilder );
modelBuilder.Entity<ApplicationUser>()
.HasMany( p => p.ChildUsers )
.WithMany()
.Map( m =>
{
m.MapLeftKey( "Father_Id" );
m.MapRightKey( "Son_Id" );
m.ToTable( "father_son_relation" );
} );
}
}
Additionally, when you need to add Children to the parent ApplicationUser, you will need to do some tweaking as you are about to insert so that it updates the database correctly. I definitely want the UserManager to do the creation of the user for me, but that means that when I go to add the user to my list of Children with the code below, it tries to add it again and throws an exception because it already exists.
var result = await UserManager.CreateAsync( user, model.Password );
var myUserId = User.Identity.GetUserId();
var users = AppDbContext.Users.Where( u => u.Id == myUserId ).Include( u => u.ChildUsers );
var u2 = users.First();
u2.ChildUsers.Add( user );
await AppDbContext.SaveChangesAsync();
After finding this question, I researched the EntityStates and found that adding the following line before calling SaveChanges resolved the exception and it no longer attempts to add it again.
AppDbContext.Entry( user ).State = EntityState.Unchanged;
TADA!!! Now to select them from the database using EF, you can then use the following code:
AppDbContext.Users.Where( u => u.Id == myUserId ).Include( u => u.Children ).First();
Since I am only getting one level of Children this will work ok, after that you risk circular references.
Comments and ideas to improve the code are welcome.

Entity Framework Core: issue with Contains method

There is my simplified model of db:
public class Chat
{
public ICollection<ApplicationUser> Users {get; set;} //nav property - represents participants of a chat
}
public class ApplicationUser : IdentityUser // it represents a net-identity user; it does not have any references to chats
{...}
So, in controller's class I try to get chats such as contain current user as a participant:
var user = GetUser();
_context.Chats.Where(chat => chat.Users.Contains(user)).ToList();
This code throws exception:
You can not use the type of expression ...ApplicationUser for
parameter's type
"Microsoft.EntityFrameworkCore.Storage.ValueBuffer" of method "Boolean
Contains[ValueBuffer](System.Collections.Generic.IEnumerable`1[Microsoft.EntityFrameworkCore.Storage.ValueBuffer],
Microsoft.EntityFrameworkCore.Storage.ValueBuffer)"
What is the problem here?
You need use Any(), like this
var chatsList =_context.Chats.Where(chat => chat.Users.Any(u => u.id== user.id)).ToList();

How can I extend ApplicationUser in ASP.NET Identity but with properties that can be null?

I would like to extend Application User. Here's an example:
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity>
GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
I tried this but it seems like when I login if any of these properties is set to a null in the database then when the /Token call is made it returns with an error.
Can someone tell me. Do I need to make a change to the way these properties are set here or in another place?
If i understand your question correctly, a simple solution to your problem could be to create a nullable type. Can you please share what you would like to do? Create a custom identity provider, for example?

Store single instance in DbContext with ASP.NET MVC 5 CF EF (no list)

I have a class called AppSettings where I store some settings of my application. So far, I only used Lists in my DbContext like
public class MyDbContext: DbContext {
public DbSet<User> Users { get; get; }
}
But for the settings, I need no list. I only want to store a single instance of my AppSettings class. I tried to set it as a normal member
public class AppSettingsContext: DbContext {
public AppSettings AppSetting { get; get; }
}
But this is not working: EF will throw an exception that the entity type AppSettings is not a part of the model for the current context. The Code:
using(var db = new AppSettingsContext()) {
var setting = new AppSettings() {
AttributeA = "Test",
//...
};
db.Entry(setting).State = EntityState.Added;
db.SaveChanges();
}
Is it possible to do this with EF? Or am I forced to implement this logic on my own by using a not mapped attribute where I make sure that only one single instance is stored and returned by the database?
If you want to store your settings in the DB, you can't store singular, that's not how TSQL works.
If you only want singular settings for a user, I would recomend web.config. If you REALLY want to store it in the DB though and want it to have a more concrete feeling you could just extend your database context like so:
public class MyDbContext: DbContext {
public DbSet<User> Users { get; get; }
public DbSet<AppSettings> AppSettings { get; set;}
}
public static class MyDbExtensions
{
public static async Task<AppSettings> DbSettings(this MyDbContext context, Guid settingsGuid)
{
return await context.AppSettings.FirstAsync(as => as.Id == settingsGuid)
}
// OR
public static async Task<AppSettings> UserSettings(this MyDbContext context)
{
return await context.AppSettings.FirstAsync(as => as.Id == UserSettingsDbGuid)
}
public static Guid UserSettingsDbGuid = "Guid of user settings goes here"
}
// example usage:
var context = GETDBCONTEXTMETHOD();
var userSettings == context.DbSettings(MyDbExtensions.UserSettingsDbGuid);
// OR
userSettings == context.UserSettings();

What Type (class) do i use for a property in my POCO for Asp.net Identy User

I have a codefirst POCO, and i want to specify a LastEditUser from my current ASP.NET IDENTITY user. I tried type ApplicationUser that gets generated with the new project. but it just saves as null.
Here is my current Attempt
public class SomeClass
{
public string SomeProperty { get; set; }
public ApplicationUser LastEditMember { get; set; }
}
And here is how i try to save it in my controller.
string currentUserId = User.Identity.GetUserId();
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);
instannceOfSomeClass.LastEditMember = currentUser;
After loading this again. the LastEditMember property is null.
I would suggest using the UserManager class to get the user object instead of working with the DbContext object. You can use UserManager.FindByIdAsync(currentUserId) to get the user. Also I am considering that this code is hit only after a user logs into the application else the currentUserId will be null

Resources