EF List To Class - c#

I have a table named UserRoles and a user can have multiple Roles.My structure is;
public class UserRole
{
[Key, Column("ID")]
public long Id { get; set; }
[ForeignKey("UserId")]
public User User { get; set; }
[Column("USERID")]
public long UserId { get; set; }
[ForeignKey("RoleId")]
public Role Role { get; set; }
[Column("ROLEID")]
public long RoleId { get; set; }
}
I want to display them in a grid grouped by userID.Do i need a new data structure?
PS: I am getting data in List<UserRoles> format.

db.UserRoles.Include("User").Include("Role").OrderBy(ur => ur.UserId).ToList();
If you don't need to show User or Role details just remove Include.
EDIT
db.Users.Include("UserRoles.Role").Select(u => new { u.UserId, Roles = string.Join(",", u.UserRoles.Select(ur => ur.Role.RoleId)) }).ToList();
Entity User should have navigation property UserRoles:
public virtual List<UserRole> UserRoles { get; set; }

Related

Nested filtering statements in Entity Framework query

As you can see here I have two entities that are linked with each other in two ways.
First way is classic many to many by two ICollection and second is by entity GroupRole which specifies role of user for particular group.
The problem is that User stores his roles for every group and Group stores roles of each user for itself.
I'd like to retrieve all groups including it's users but only with particular role, unfortunately it seems like when I use Include statement and then nest inside of it Where I cannot use Group entity representation within nested statement and it throws an error
LINQ statement couldn't be translated because of 'g' within Include statement
If anyone could drop some hint how to work around this problem I would be very glad.
Thanks
var result = await groupsRepository.Query(tracking: false)
.Include(g => g.Users.Where(u => u.GroupRoles.Any(r => r.Role == GroupRolesEnum.ExampleRole && r.GroupId == g.GroupId))).
.ToListAsync();
public class Group
{
public string Name { get; set; }
public Guid GroupId { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<GroupRole> UsersRoles { get; set; }
}
public class User
{
public Guid UserId { get; set; }
public string Email { get; set; }
public ICollection<Group> Groups{ get; set; }
public ICollection<GroupRole> GroupRoles { get; set; }
}
public class GroupRole
{
public Guid UserId { get; set; }
public Guid GroupId { get; set; }
public GroupRolesEnum Role { get; set; }
public virtual Group Group{ get; set; }
public virtual User User { get; set; }
}

Explicit Loading nested related models in Entity Framework

I'm working on an ASP.NET MVC5 project using EF6. I have 3 models: user, role and permission.
The relation between user and role is many to many. The relation between role and permission is many to many.
LazyLoadingEnabled is disabled in the database context.
public class Permission
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
public class Role
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Permission> Permissions { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class User
{
public int ID { get; set; }
public string Username { get; set; }
public string DisplayName { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
public class TaskManagerDB : DbContext
{
public TaskManagerDB() : base()
{
Configuration.LazyLoadingEnabled = false;
}
public DbSet<Role> Roles { get; set; }
public DbSet<Permission> Permissions { get; set; }
public DbSet<User> Users { get; set; }
}
At an earlier point, I fetch a given user:
User user = db.Users.Find(1);
Now: since I already have the model, how can I load the user roles with their permissions?
I have tried:
db.Entry(user).Collection(x => x.Roles).Query().Include(y => y.Permissions).Load();
But it's not working - user.Roles is still null.
The following solution is not acceptable because I already have the user Model:
User user = db.Users.Include("Roles.Permissions").Where(x => x.ID == 1).FirstOrDefault();
What you have tried
db.Entry(user).Collection(x => x.Roles).Query()
.Include(y => y.Permissions)
.Load();
is indeed the intended way. And it works for everything else except the many-to-many relationship with implicit junction table, which is the case here.
I don't know if it's a bug or "by design", but the solution is to Include the other (calling) end of the relationship, e.g.
db.Entry(user).Collection(x => x.Roles).Query()
.Include(y => y.Users) // <--
.Include(y => y.Permissions)
.Load();
One way of getting the roles and permissions for a user:
db.Roles.Include("Permissions").Where(r => r.Users.Select(u => u.ID).Contains(user.ID));

How to handle self references in Entity Framework code-first?

These are my models (simplified):
public User()
{
Friends = new HashSet<User>();
Subscriptions = new HashSet<Subscription>();
Tasks = new HashSet<Task>();
Invitations = new HashSet<Invitation>();
Events = new HashSet<Event>();
}
public Guid UserId { get; set; }
public DateTime MemberSince { get; set; }
[StringLength(450)]
[Index("UserNameIndex", IsUnique = true)]
public string NickName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAdress { get; set; }
public string HashedPassword { get; set; }
public virtual ProfilePicture ProfilePicture { get; set; }
public bool Validated { get; set; }
ICollection<Event> Events { get; set; }
ICollection<User> Friends { get; set; }
And the Event model:
public class Event
{
public string EventName { get; set; }
public Guid EventId { get; set; }
public Guid UserId { get; set; }
public DateTime? Time { get; set; }
public string Location { get; set; }
public DateTime? EventDate { get; set; }
public virtual User User { get; set; }
public ICollection<User> Participants { get; internal set; }
}
Here's the model creation:
modelBuilder.Entity<User>().HasKey(u => u.UserId);
modelBuilder.Entity<User>().
HasMany<User>(u => u.Friends).
WithMany();
modelBuilder.Entity<User>().
HasMany<Event>(u => u.Events).
WithMany();
Now the problem is the following: my tables look like this:
It seems like the relations are not the way they should be...
User table:
Event table:
Automatically created UserEvents:
Now what I expected is when creating a new Event (UserId) is required there. I get a new Entry in the Events table + a new one in the UserEvents....
What am I missing here ?
You have two different relations between User and Event. A one-to-many relation and a many-to-many relation.
The first is a one-to-many relationship between the event and the creator of the event (The user and userid properties on Event)
When you add a new Event with the required UserId, there will not be a record created in the automatically created UserEvents table, because you have a one-to-many relationship here. So simply creating an Event with the userid will not lead to a record in the UserEvents table.
The second is the many-to-many relationship between Event and it's participants. When you add an event with participants. There would be records also inserted into the UserEvents table. Only participants will appear in the UserEvents table. You should however create your many-to-many mapping with a reference to your property Participants in the Event class to make this possible.
modelBuilder.Entity<User>().HasMany<Event>(u => u.Events).WithMany(m => m.Participants);

How to add a role to use when EF doesn't bring in UserRoles Table?

I have a UserRoles table with just two columns userId and RoleId and entityframework doesn't bring that class in. How can save the association without the userroles class?
my users and roles classes in EntityFramework are like this.
public partial class aspnet_Users
{
public aspnet_Users()
{
this.aspnet_Roles = new HashSet<aspnet_Roles>();
}
public System.Guid ApplicationId { get; set; }
public System.Guid UserId { get; set; }
public string UserName { get; set; }
public string LoweredUserName { get; set; }
public string MobileAlias { get; set; }
public bool IsAnonymous { get; set; }
public System.DateTime LastActivityDate { get; set; }
public virtual aspnet_Applications aspnet_Applications { get; set; }
public virtual aspnet_Membership aspnet_Membership { get; set; }
public virtual ICollection<aspnet_Roles> aspnet_Roles { get; set; }
}
public partial class aspnet_Roles
{
public aspnet_Roles()
{
this.aspnet_Users = new HashSet<aspnet_Users>();
}
public System.Guid ApplicationId { get; set; }
public System.Guid RoleId { get; set; }
public string RoleName { get; set; }
public string LoweredRoleName { get; set; }
public string Description { get; set; }
public virtual aspnet_Applications aspnet_Applications { get; set; }
public virtual ICollection<aspnet_Users> aspnet_Users { get; set; }
}
EF doesn't give me UserRoles class in model but it shows up in XML.
when i try to add a new user, i am accessing like this
var role = new Data.aspnet_Roles();
role.RoleId = userItem.roles.First().RoleId;
role.RoleName = userItem.roles.First().RoleName;
user.aspnet_Roles.Add(role);
This gives a error
InnerException {"Cannot insert duplicate key row in object 'dbo.aspnet_Roles' with unique index 'aspnet_Roles_index1'.\r\nThe statement has been terminated."} System.Exception {System.Data.SqlClient.SqlException}
the answer here suggest that it should work. i cant figure out what i am doing wrong.
Entity Framework Add User to Role
It also makes sense that i get this error. But I am clueless on how else i can store the userroles relationship without having userroles EF class. I am really stuck. Any help is appreciated. Thank you.
The way you are doing this job, you are creating a new role with the same id and name that exists in database now, because you are using an instance of role that doesn't exists in context and this way, context thinks it is a new role and should be added.
You should inform the context that this is not a new role, to do so:
you can load the role you need, using a query, into the same context that you will use to save user
or you can attach (entry) the role object to the same context that you will use to save user, and set its state to unchanged.
For example you can first find the role yo want:
var db= new YourContext();
var role = db.aspnet_Roles.Where(....).FirstOrDefault();
then using that instnace of role and that instance of context:
user.aspnet_Roles.Add(role);
db.SaveChanges();

Are my tables linked correctly for Entity Framework?

Forewarning: I know approximately nothing when it comes to MVC/Entity Framework/Linq queries.
I'm having an issue when I try to query the database. Here's the query I'm using:
int? UserId = db.StudentModel
.Where(c => c.UserName == certUserName)
.Select(c => c.UserId)
.FirstOrDefault();
When it searches the database, it successfully retrieves the UserId.
The problem is that I then use the following query:
CompletionsModel student = db.Completions.Find(UserId);
When I do this, it throws an inner exception that states
{"Invalid column name 'UserProfile_UserId'."}
The weird thing is that when I go to my code and mouse over the 'db' part of the command to see what data it's holding, it has CourseModel, StudentModel, and Completions (though the model's actual filename is CompletionsModel - is that a clue?), so it seems like they're linked properly.
Here's the code for my three models and the database context.
CompletionsModel (UserProfile is white text in my code; not sure why it's teal here Same with UserId and CompletionDate):
[Table("Completion")]
public class CompletionsModel
{
[Key]
public int UserId { get; set; }
public string PRD_NUM { get; set; }
public DateTime CompletionDate { get; set; }
public virtual CourseModel PRD { get; set; }
public virtual StudentModel UserProfile { get; set; }
}
CourseModel:
[Table("PRD")]
public class CourseModel
{
[Key]
public string PRD_NUM { get; set; }
public string PRD_TIT { get; set; }
//because any number of students can be enrolled in one course
public virtual ICollection<CompletionsModel> CompletionsModel { get; set; }
}
StudentModel:
[Table("UserProfile")]
public class StudentModel
{
[Key]
public int UserId { get; set; }
public string UserName { get; set; }
public virtual ICollection<CompletionsModel> CompletionsModel { get; set; }
}
DBContext:
public class ClassContext : DbContext
{
public ClassContext()
: base("DefaultConnection")
{
}
public DbSet<StudentModel> StudentModel { get; set; }
public DbSet<CompletionsModel> Completions { get; set; }
public DbSet<CourseModel> CourseModel { get; set; }
}
And finally, an image of my database layout - maybe this will help things along, too:
I'm too at the beginning of Entity Framework, but what does irritate me is, that you have kind of foreign key relationship between Completion and UserProfile, without really defining, a int column as foreign key in your Completion Table.
You could try to change
public virtual StudentModel UserProfile { get; set; }
to something like
public virtual int StudentId { get; set; }
[ForeignKey("StudentId")]
public virtual StudentModel UserProfile { get; set; }
The same for PRD
But maybe a change in your database is not what you want.
What you could also do, is to remove these lines
public virtual CourseModel PRD { get; set; }
public virtual StudentModel UserProfile { get; set; }
Hope that helps.
EDIT:
I guess the problem is, that you are missing the ForeignKey Attribute at your UserProfile property in your Completions table.
So use
[ForeignKey("UserId")]
public virtual StudentModel UserProfile { get; set; }
instead of
public virtual StudentModel UserProfile { get; set; }
if the UserIds are representing the same user

Categories

Resources