C
C#2y ago
Gage

✅ Mapping an Identity user to an instance of an EF core model ID

Any suggestions on how to make an identity user have a model ID? I need to do this so I can have a custom view for all users . My plan was to just use loops and only show content where IDs match up. Not sure where to begin.
53 Replies
Angius
Angius2y ago
What do you mean by "model ID"? Do you have an entity Model and want to create a relationship between it and the user?
Gage
Gage2y ago
Yes
Angius
Angius2y ago
Then just reference it
public IdentityUser User { get; set; }
public IdentityUser User { get; set; }
Or create a custom user class if you want, by extending IdentityUser
Gage
Gage2y ago
{
public class IndexModel : PageModel
{
private readonly ApplicationDbContext _context;
public IdentityUser Entity { get; set; }

public Student Student { get; set; }
public Teacher Teacher { get; set; }

public IndexModel(ApplicationDbContext context)
{
_context = context;
}

public void OnGet()
{
Entity = _context.Users.Find(User.Identity!.Name);
Student = _context.Students.Find(Entity.Id);
Teacher = _context.Teachers.Find(Entity.Id);
}
}
}
{
public class IndexModel : PageModel
{
private readonly ApplicationDbContext _context;
public IdentityUser Entity { get; set; }

public Student Student { get; set; }
public Teacher Teacher { get; set; }

public IndexModel(ApplicationDbContext context)
{
_context = context;
}

public void OnGet()
{
Entity = _context.Users.Find(User.Identity!.Name);
Student = _context.Students.Find(Entity.Id);
Teacher = _context.Teachers.Find(Entity.Id);
}
}
}
How would I get this to line up? I need to see if the Entity (The Identity User) Is the Student or the Teacher. I dont think the code I have so far would work
Angius
Angius2y ago
You can use roles for that Instead of two different types of a user
Gage
Gage2y ago
so we were suppose to use claims, And I have working claims. Now how would I make each individual user have a seperate instance? Example would be if a student wanted to view their specific courses or grades. how would that be done?
Angius
Angius2y ago
await _context.Grades.Where(g => g.StudentId == id).ToListAsync();
await _context.Grades.Where(g => g.StudentId == id).ToListAsync();
Gage
Gage2y ago
okay that creates a where clause that connects grades to student. I have that as well
Angius
Angius2y ago
A grade would be something like
class Grade
{
public User Student { get; set; }
public int StudentId { get; set; }
public User Teacher { get; set; }
public int TeacherId { get; set; }
}
class Grade
{
public User Student { get; set; }
public int StudentId { get; set; }
public User Teacher { get; set; }
public int TeacherId { get; set; }
}
Gage
Gage2y ago
wait a minute so I have this for my Grade
{
public class Grade : EntityBase
{
[Required]
public int StudentId { get; set; }
public Student Student { get; set; }
[Required]
public int ActivityId { get; set; }
public Activity Activity { get; set; }
public DateTime SubmittedOn { get; set; }
public int PointsEarned { get; set; }
public string Comments { get; set; }

public Grade()
{

}
}
}
{
public class Grade : EntityBase
{
[Required]
public int StudentId { get; set; }
public Student Student { get; set; }
[Required]
public int ActivityId { get; set; }
public Activity Activity { get; set; }
public DateTime SubmittedOn { get; set; }
public int PointsEarned { get; set; }
public string Comments { get; set; }

public Grade()
{

}
}
}
Angius
Angius2y ago
That also works, sure My example was a very simple "teacher gives grade"
Gage
Gage2y ago
and I have this for my student
{
public class Student : EntityBase
{
public int DepartmentID { get; set; }
public Department Major { get; set; }
public Teacher Advisor { get; set; }
public List<Enrollment> Enrollments { get; set; }
public List<Grade> Grades { get; set; }
[Required, MaxLength(100)]
public string FirstName { get; set; }
[Required, MaxLength(100)]
public string LastName { get; set; }
public DateTime DoB { get; set; }
[Phone]
public string Phone { get; set; }
[EmailAddress]
public string Email { get; set; }

public Student()
{
Enrollments = new List<Enrollment>();
Grades = new List<Grade>();
}
}
}
{
public class Student : EntityBase
{
public int DepartmentID { get; set; }
public Department Major { get; set; }
public Teacher Advisor { get; set; }
public List<Enrollment> Enrollments { get; set; }
public List<Grade> Grades { get; set; }
[Required, MaxLength(100)]
public string FirstName { get; set; }
[Required, MaxLength(100)]
public string LastName { get; set; }
public DateTime DoB { get; set; }
[Phone]
public string Phone { get; set; }
[EmailAddress]
public string Email { get; set; }

public Student()
{
Enrollments = new List<Enrollment>();
Grades = new List<Grade>();
}
}
}
so how would I make this student a user?
Angius
Angius2y ago
You wouldn't have a student You'd just have a user You can make your student a user if you inherit from IdentityUser though
Gage
Gage2y ago
We were given this diagram to follow, is it possible following this diagram?
Gage
Gage2y ago
I'm implementing it incorrectly, not sure
Angius
Angius2y ago
Angius
Angius2y ago
There's no multiple inheritance in C#
Gage
Gage2y ago
yeah 😦
Angius
Angius2y ago
A class can inherit only from one other class So it's impossible to recreate this graph 1:1 while using Identity at the same time
Gage
Gage2y ago
could I make a middle man class for instances like these?
Angius
Angius2y ago
How would that work?
Gage
Gage2y ago
That's frustrating Think I should just ignore what the professor was saying then? He wanted us to use Identity with that, But it seems like you are saying what I was thinking in that it's not going to line up correctly
Angius
Angius2y ago
IdentityUser has to be somewhere Either as related data, or as a parent class
Gage
Gage2y ago
What if I made Identity user a field in student and teacher?
Angius
Angius2y ago
You could have
class BaseUser : IdentityUser
{
public UserType UserType { get; set; }
public Student? Student { get; set; }
public int? StudentId { get; set; }
public Teacher? Teacher { get; set; }
public int? TeacherId { get; set; }
}

enum UserType
{
Student,
Teacher
}
class BaseUser : IdentityUser
{
public UserType UserType { get; set; }
public Student? Student { get; set; }
public int? StudentId { get; set; }
public Teacher? Teacher { get; set; }
public int? TeacherId { get; set; }
}

enum UserType
{
Student,
Teacher
}
Gage
Gage2y ago
oh that is interesting
Angius
Angius2y ago
And, yeah, put a nav property to BaseUser inside of both Student and Teacher
Gage
Gage2y ago
never heard that term. What is a nav property? Same as a field?
Angius
Angius2y ago
You'd need to at least also change the class your DbContext inherits from, from IdentityContext to IdentityContext<BaseUser> $structure
MODiX
MODiX2y ago
namespace Namespace;

[Attribute]
public class Class
{
public string PublicField;
private bool _privateField;
protected double protectedField;

public int PublicProperty { get; set; }

public Class() {} // Constructor

public void Method(int parameter)
{
var localVariable = parameter;
}
}
namespace Namespace;

[Attribute]
public class Class
{
public string PublicField;
private bool _privateField;
protected double protectedField;

public int PublicProperty { get; set; }

public Class() {} // Constructor

public void Method(int parameter)
{
var localVariable = parameter;
}
}
For C# versions older than 10, see $StructureOld
Angius
Angius2y ago
Properties have the { get; set; }
Gage
Gage2y ago
oh I see
Angius
Angius2y ago
"nav properties" or "navigation properties" are an EF term for properties that point to other database models Since you can use them to navigate from one model to another
await _context.Users.Select(u => new {
Blogs = u.Blogposts, // navigating to user's blogposts
Categories = u.Blogposts.SelectMany(b =>
b.Categories.Select(c => c.Name) // navigating to blogposts, then to their categories
)
})
.ToListAsync()
await _context.Users.Select(u => new {
Blogs = u.Blogposts, // navigating to user's blogposts
Categories = u.Blogposts.SelectMany(b =>
b.Categories.Select(c => c.Name) // navigating to blogposts, then to their categories
)
})
.ToListAsync()
for example
Gage
Gage2y ago
wait, If I am doing it like that, would I need to put ApplicationDBContext in the student and teacher Models as well?
Angius
Angius2y ago
No, why? DbContext represents the database
Gage
Gage2y ago
Im looking at where you did _context
Angius
Angius2y ago
It's not a table Yeah, it's a reference to your DbContext
public class MyCoolDbContext : IdentityContext<MyUser>
{
public DbSet<MyUser> Users { get; set; }
public DbSet<Blogpost> Blogposts { get; set; }
public DbSet<Category> Categories { get; set; }
}
public class MyCoolDbContext : IdentityContext<MyUser>
{
public DbSet<MyUser> Users { get; set; }
public DbSet<Blogpost> Blogposts { get; set; }
public DbSet<Category> Categories { get; set; }
}
public class MyUser : IdentityUser
{
public List<Blogpost> Blogposts { get; set; }
}

public class Blogpost
{
public MyUser Author { get; set; }
public string AuthorId { get; set; }
public List<Category> Categories { get; set; }
}

public class Category
{
public List<Blogpost> Blogposts { get; set; }
}
public class MyUser : IdentityUser
{
public List<Blogpost> Blogposts { get; set; }
}

public class Blogpost
{
public MyUser Author { get; set; }
public string AuthorId { get; set; }
public List<Category> Categories { get; set; }
}

public class Category
{
public List<Blogpost> Blogposts { get; set; }
}
My imaginary scenario looks somewhat like this
Gage
Gage2y ago
Oh okay, now I think I am back on track. I think I get what you mean Would this map the Identity User to the Model correctly then?
public class Student : EntityBase
{
public BaseUser User { get; set; }
public int DepartmentID { get; set; }
public Department Major { get; set; }
public Teacher Advisor { get; set; }
public List<Enrollment> Enrollments { get; set; }
public List<Grade> Grades { get; set; }
[Required, MaxLength(100)]
public string FirstName { get; set; }
[Required, MaxLength(100)]
public string LastName { get; set; }
public DateTime DoB { get; set; }
[Phone]
public string Phone { get; set; }
[EmailAddress]
public string Email { get; set; }

public Student()
{
Enrollments = new List<Enrollment>();
Grades = new List<Grade>();
}
}
public class Student : EntityBase
{
public BaseUser User { get; set; }
public int DepartmentID { get; set; }
public Department Major { get; set; }
public Teacher Advisor { get; set; }
public List<Enrollment> Enrollments { get; set; }
public List<Grade> Grades { get; set; }
[Required, MaxLength(100)]
public string FirstName { get; set; }
[Required, MaxLength(100)]
public string LastName { get; set; }
public DateTime DoB { get; set; }
[Phone]
public string Phone { get; set; }
[EmailAddress]
public string Email { get; set; }

public Student()
{
Enrollments = new List<Enrollment>();
Grades = new List<Grade>();
}
}
Angius
Angius2y ago
Then
[Controller]
public class UserController : ControllerBase
{
private readonly MyCoolDbContext _context;

public UserController(MyCoolDbContext context)
{
_context = context;
}

[HttpGet]
public async Task<List<List<string>>> GetNamesOfCategoriesForUsers()
{
var categories = await _context.Users.Select(u => new {
Blogs = u.Blogposts, // navigating to user's blogposts
Categories = u.Blogposts.SelectMany(b =>
b.Categories.Select(c => c.Name) // navigating to blogposts, then to their categories
)
})
.ToListAsync()
return categories;
}
}
[Controller]
public class UserController : ControllerBase
{
private readonly MyCoolDbContext _context;

public UserController(MyCoolDbContext context)
{
_context = context;
}

[HttpGet]
public async Task<List<List<string>>> GetNamesOfCategoriesForUsers()
{
var categories = await _context.Users.Select(u => new {
Blogs = u.Blogposts, // navigating to user's blogposts
Categories = u.Blogposts.SelectMany(b =>
b.Categories.Select(c => c.Name) // navigating to blogposts, then to their categories
)
})
.ToListAsync()
return categories;
}
}
LGTM
Gage
Gage2y ago
yeah! Okay good so I did the controllers correctly alright I am going to test this out 😅 should I drop the previous database and delete the migrations? I think I will just to be safe
Angius
Angius2y ago
It's a big change, so yeah, probably Just make sure to commit what you have Just so you can revert the code should anything go awry
Gage
Gage2y ago
yeah I've got several backups at this point lmfao
Angius
Angius2y ago
Hope you're using Git, not a bunch of myproject1.zip myproject2.zip myproject3wtf.zip lol
Gage
Gage2y ago
oh snap, So I used scaffolding to make my controllers. I should regenerate those as well since the model changed?
Angius
Angius2y ago
Or modify them by hand
Gage
Gage2y ago
yeah..... code gen it is haha
Angius
Angius2y ago
Generally, it's a better idea to not use scaffolding. The code it generates is... good for tiny little test projects, but not for production, let's just say
Gage
Gage2y ago
Is it normal to have heart palpitations here?
Angius
Angius2y ago
With big changes? Yes 😄
Gage
Gage2y ago
So I made an admin account and I went to add a teacher to the teacher scaffold. It does not look like its asking for a user here?
Gage
Gage2y ago
Same with student
Gage
Gage2y ago
That Did not work
Accord
Accord2y ago
Closed!