19

In a VS 2013 RTM, MVC 5 project with EF 6, I tried to scaffold a controller based on the ApplicationUser (default with individual accounts authentication). Both ApplicationUser and IdentityUser are mapped to a Users table. The wizard opens the context file for editing and tries to add a new db set for ApplicationUser (ApplicationUsers) and then fails with this error:

Unable to retrieve metadata for ApplicationUser. Multiple object sets per type are not supported. The object sets ApplicationUsers and Users can both contain instances of type ApplicationUser The solution does not have any reference to, or instance of ApplicationUsers.

Is this a known issue? Can the scaffolding be run using command line with options (from PMC)? Note: scaffolding also adds an extra db set to the context class if I specify a model that references ApplicationUser (the app works if I remove it and fix references in the generate controller).

Amir Ismail
  • 3,865
  • 3
  • 20
  • 33
AKhooli
  • 1,285
  • 1
  • 13
  • 11

8 Answers8

32

Wow. I'm really surprise that no one actually got to the root of this, and instead, are just recommending workarounds.

IdentityDbContext already contains a property:

`public virtual IDbSet<TUser> Users { get; set; }

When you subclass IdentityDbContext to create your own application-specific context, you must specify what class satisfies the TUser generic. The default is:

public ApplicationDbContext : IdentityDbContext<ApplicationUser>

Which then means that you functionally have a property already via inheritance in the form of:

public IDbSet<ApplicationUser> Users { get; set; }

If you then add another property to your application-specific context such as:

public DbSet<ApplicationUser> ApplicationUsers { get; set; }

You now have the same entity tracked by two DbSets, and you get that error. The solution? Simply don't add your own DbSet for ApplicationUser. There's no need to rename or override anything.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • 3
    The problem is that DbSet gets added automatically during the scaffolding. – Drazen Bjelovuk Sep 15 '14 at 05:32
  • During what scaffolding? Aside from the initial scaffolding that's part of the project template, nothing else touches your context automatically. – Chris Pratt Sep 15 '14 at 14:00
  • 4
    When adding a controller with views using Entity Framework for the ApplicationUser class. – Drazen Bjelovuk Sep 15 '14 at 16:39
  • 2
    That's surprising, but if that's the case, then either don't use scaffolding or delete the added line after scaffolding is complete. – Chris Pratt Sep 15 '14 at 17:04
  • Only real option seems to be the former, as the added DbSet prevents the scaffolding from actually completing. – Drazen Bjelovuk Sep 15 '14 at 17:07
  • Thank you thank you thank you!! This just saved me. I was scratching my head wondering where the heck Users was coming from. Wish I could upvote more. – Ryan Drost Oct 30 '14 at 13:45
  • The automatically added DbSet was also the case for me. I was scaffolding a view modeling the ApplicationUser, so I had to delete the DbSet line from the IndendityUser class in Models. Works like a charm now. – Scopperloit Mar 11 '15 at 20:18
  • This is it! After all those bulky workarounds which doesn't even work and causes even more weird errors, this is the fix and it's so elegant. – doncadavona May 22 '15 at 03:45
  • @ChrisPratt I have some additional properties for user profiles in ApplicationUser class. If I don't add my own DbSet of ApplicationUser, I can't access those properties. What to do for this problem? – SeyedPooya Soofbaf Oct 21 '15 at 12:07
  • Not sure what you mean. Having a separate DbSet or using the one on IdentityDbContext makes no difference. Either way, you still need to query to return the actual user instance. – Chris Pratt Oct 21 '15 at 15:46
  • Best answer about this subject. – BillRuhl Oct 28 '15 at 16:38
17

Short-Version: Rename your ApplicationUser class to User.

I've been running into this problem for about a month with absolutely no luck...until now!

Initially, I thought it was a preview issue, but after persisting into the RTM along with the latest libraries, I became incredibly annoyed, since this problem persisted into Migrations too.

However, IdentityDbContext, according to the error message, seems to be creating two DbSets: ApplicationUsers and Users. We only want Users when looking at the source code:

public class IdentityDbContext<TUser> : DbContext where TUser : Microsoft.AspNet.Identity.EntityFramework.IdentityUser
{
    ...
    public virtual IDbSet<TUser> Users { get; set; }
    ...
}

From this, we (and the scaffolding engine, and the migrations engine) should only see "Users", not "ApplicationUsers".

To rectify this situation, you will need to adjust your application class to account for this rather strange error. Simply rename your ApplicationUser class to User:

using Microsoft.AspNet.Identity.EntityFramework 
...
public class ApplicationUser : IdentityUser
{
    Your Stuff
}

To:

using Microsoft.AspNet.Identity.EntityFramework 
...
public class User: IdentityUser
{
    Your Stuff
}

Attempt to Scaffold again. If you receive another error along the lines of the class cannot be found, save your project, close VS2013, re-open VS2013, load the project, re-build the project, and finally attempt to scaffold. The IdentityDBContext should no longer be creating a dummy "ApplicationUsers" DBSet object causing both Entity Migrations and Scaffolding to issue these errors.

Hope this helps!

P.S. Any mapping done ought not to affect this problem, so you should be able to still map to the same table if you wish to.

EDIT: If you receive further problems, undo the rename. I ran into some problems (more scaffolding and query errors), and after I went back to ApplicationUser, those problems disappeared and the problem above did not re-occur. Just a heads up.

James Haug
  • 1,426
  • 12
  • 27
  • +1 for the workaround, James. Would be great to hear from the VS 2013 people and make sure the next update will not break existing code. – AKhooli Dec 10 '13 at 06:03
  • 1
    I got it in the end, had another issue when this line was somehow added to my IdentityModel.cs file: public System.Data.Entity.DbSet Users { get; set; } so had to remove it. – Stuart Dobson Dec 21 '13 at 04:02
  • Actually, since it's public virtual IDbSet Users { get; set; } you should override it. – Cody James Christian Mar 19 '14 at 03:00
  • You can override it, but, theoretically, that won't solve the problem of an ApplicationUsers class still being created alongside the wanted Users class. – James Haug Mar 19 '14 at 17:04
7

Read the above problems en solutions. My error text was:

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

I suspect the error was created when I was playing around and scaffolded the model: ApplicationUser in a new controller.

Solved it by removing the below from : ApplicationDbContext.cs

    public System.Data.Entity.DbSet<DataLayerIdentity.Models.ApplicationUser> ApplicationUsers
    {
        get;
        set;
    }

No Other changes where made to solve the problem. I hope this helps someone.

Visualcoach
  • 111
  • 1
  • 5
  • Thanks Patrick, this was exactly what I had done. When you scaffold the ApplicationUser into a new controller, it was adding that line. – BillD Jan 14 '15 at 21:35
  • This is the right solution to this problem. Thanks. – Anthony Jan 21 '15 at 21:47
7

When you use scaffolding to generate control, vs will auto insert 1 line to your db context

public System.Data.Entity.DbSet<...API.Models.ApplicationUser> ApplicationUsers { get; set; }

Just delete that line, and in your controller. change db.ApplicationUsers to db.Users

Wolf
  • 6,361
  • 2
  • 28
  • 25
1

Here is the simplest solution. When you add/scaffold a view (list) based on ApplicationUser as the model, VS2013 ADDS the following to the IdentityModels.vb or .cs file.:

Public Property ApplicationUsers As System.Data.Entity.DbSet(Of ApplicationUser)

Just remove this property and the problem goes away.

Matthew Pitts
  • 809
  • 1
  • 8
  • 13
1

If you are trying to create an ApplicationUsersController please follow these steps.

  1. Delete this line from IdentityModels.cs

    public System.Data.Entity.DbSet<Project.Models.ApplicationUser> ApplicationUsers { get; set; }
    
  2. Build the project

    control + shift + b
    
  3. Generate the controller

    Right click on the 'Controllers' folder.
    Add > Controller
    MVC Controller with views, using Entity Framework
    Model Class: ApplicationUser
    Add
    
  4. Go back to IdentityModels.cs and delete this line AGAIN

    public System.Data.Entity.DbSet<Project.Models.ApplicationUser> ApplicationUsers { get; set; }
    
  5. Build the project

    control + shift + b
    
  6. Change the database calls to from ApplicationUsers to Users in ApplicationUsersController.cs

    control + f to bring up 'Find and Replace'
    Click 'Replace in files'
    Find what: db.ApplicationUsers
    Replace with: db.Users
    Replace All
    
  7. Press play and cross fingers :)

Matt
  • 33,328
  • 25
  • 83
  • 97
0

What you can also do: Create an empty controller, and add the code for the DataContext yourself

    protected ApplicationDbContext db { get; private set; }

    public HomeController() : this(new ApplicationDbContext())
    {
    }

    public HomeController(ApplicationDbContext db)
    {
        this.db = db;
    }

Then create your methods like Index, Create and so on, and create the views with right-clicking and "Add view..." for each. Scaffold your views with the list, create, whatever template that is appropriate and choose the ApplicationUser as an model.

Important: Delete the entry in "Data context class", or you will get a similar error again. But if you leave the "Data context class" empty, the scaffolding of the view will work out fine.

Malyngo
  • 863
  • 7
  • 18
0

I fixed problem by removing DbSet from context and then changing references in controller from ApplicationUsers to Users. It worked - but now i see no point in scaffolding users. To much things has to by maintained on top level and it just does not work right. Now i know that view models and repository are the way I want to go.