Scott C
Scott C

Reputation: 55

EF6 Scaffolding /w FK to ApplicationUser fails to generate properly

This is a bit of a long winded question. I've been going through a lot trying to learn the ins and outs of EF6 and MVC5 at the same time, so I apologize if anything I'm saying is not making sense or is plain old wrong. (please let me know if it is!)

The problem is arising when I'm trying to scaffold CRUD pages for any models that have foreign keys to the pre-made AspNetUsers table. (This and a few other tables are already part of the DB if you choose a new MVC5 project with authentication.)

I've been able to successfully scaffold fully working CRUD pages for all my models that don't include links to the Users table. I'm wondering if it's something I've misunderstood, or if something I've done is messing this up.

I've been reading a lot of answers to questions here on SA for problems that are similar to mine, but to no avail. It seems to me like such a simple thing should be easier, but I've been struggling with this for days now.

To try to isolate the problem, I've started a new MVC project with authentication and done nothing other than add my models file, migrate the DB to add the tables and try to scaffold the pages. The scaffolding itself completes successfully, but adds this line to the IdentityModels.cs file:

public System.Data.Entity.DbSet<TestWhatever.Models.ApplicationUser> IdentityUsers { get; set; }

which is not correct (learned that from another SA thread). There should only be user generated dbsets in this file.

Upon running the app, I get the following error:

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

Edit: It was suggested below that I simply remove the generated IdentityUsers line - however doing that causes compiler errors in the generated CRUD pages. Something is not going right here, I'm starting to think that EntityFramework doesn't know how to use its own UserManager to display and update Users. ::

Is what I'm doing along the right path? Am I not supposed to be using the inbuilt tables for user auth? If not, why are they there? Any insight is appreciated, I've been finding this all very confusing as any documentation or answered questions I find are never covering quite the same topic. Thanks.

The tables that are giving me problems look like this:

public class ExamInProgress
{
    [Key]
    public int ProgressId { get; set; }

    [Required]
    [Display(Name = "User")]
    public string UserId { get; set; }
    [ForeignKey("UserId")]
    public ApplicationUser User { get; set; }

    [Required]
    [Display(Name = "Exam")]
    public int ExamId { get; set; }
    public virtual Exam Exam { get; set; }
}


public class CompletedExam
{
    [Key]
    public int CompletedExamId { get; set; }

    [Required]
    [Display(Name = "Date Completed")]
    public DateTime DateCompleted { get; set; }

    [Required]
    [Display(Name = "Final Score")]
    public decimal FinalScore { get; set; }

    [Required]
    [Display(Name = "Exam Name")]
    public string ExamName { get; set; }

    [Required]
    [Display(Name = "User")]
    public string UserId { get; set; }

    [ForeignKey("UserId")]
    public ApplicationUser User { get; set; }
    public virtual Exam Exam { get; set; }
}

Another example of the tables I'm using: (there are more but mainly just ints and strings)

public class Exam
{
    [Key]
    public int ExamId { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "Exam name cannot be longer than 100 characters.")]
    [Display(Name = "Exam Name")]
    public string ExamName { get; set; }

    [Display(Name = "Exam Description")]
    public string ExamDescription { get; set; }

    public virtual ICollection<Module> Modules { get; set; }
}

public class Question
{
    [Key]
    public int QuestionId { get; set; }

    [Required]
    [Display(Name = "Question Text")]
    public string QuestionText { get; set; }

    [Display(Name = "Question Order Index")]
    [Range(0, int.MaxValue, ErrorMessage = "Index can not be negative")]
    public int? QuestionOrderIndex { get; set; }

    [Required]
    [Display(Name = "Question Type")]
    public int QuestionTypeId { get; set; }

    [Required]
    [Display(Name = "Module")]
    public int ModuleId { get; set; }

    public virtual QuestionType QuestionType { get; set; }
    public virtual Module Module { get; set; }
    public virtual ICollection<Answer> Answers { get; set; }
}

public class QuestionType
{
    [Key]
    public int QuestionTypeId { get; set; }

    [Required]
    [StringLength(60, ErrorMessage = "QuestionType Name cannot be longer than 60 characters.")]
    [Display(Name = "QuestionType Name")]
    public string QuestionTypeName { get; set; }

    [Display(Name = "QuestionType Description")]
    public string QuestionTypeDescription { get; set; }

    public virtual ICollection<Question> Questions { get; set; }
}

Upvotes: 2

Views: 576

Answers (1)

Chris Pratt
Chris Pratt

Reputation: 239300

The error you're getting is due to having added the IdentityUsers property to your context. Your context is inheriting from IdentityDbContext<ApplicationUser>, and that class already has the following property:

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

Where TUser is the type passed in the generic, ApplicationUser. Adding your own DbSet for ApplicationUser creates two methods of access, and you get that error. Remove your property and you should be good.

Upvotes: 3

Related Questions