System.NotSupportedException in Entity Framework (ASP.NET MVC) - asp.net-mvc

I have an ASP.NET MVC5 project with Entity Framework. I have people (Pajtas class) which are in groups (every group has a unique number). The users can edit the people's information but only if the user has permission to the group in which the person is.
Every user has an IfiAdatlap object and the IfiAdatlap object has the permissions for the numbered groups. So I have a simple permisison class:
public class CsoportHozzaferes
{
[Required]
[Key]
[Column(Order = 1)]
public int Csoport { get; set; }
[Required]
[Key]
[Column(Order = 2)]
public virtual IfiAdatlap IfiAdatlap { get; set; }
}
In my controller I have a function to check that the current user's IfiAdatlap object has permission to the group in which the person is whose information the user would like to edit. First of all I get the current user's ApplicationUser object (user), than I try to get the list of groups (csoportok) for which the user has permission to be able to check that the person's group number (pajtas.Csoport) is in this list or not.
private void PajtasHozzaferesCheck(Pajtas pajtas)
{
var userName = User.Identity.Name;
var user = db.Users.FirstOrDefault(x => x.UserName == userName);
var csoportok = db.CsoportHozzaferesek.Where(h => h.IfiAdatlap != null && h.IfiAdatlap == user.Adatlap).Select(csh => csh.Csoport).ToList();
if (!(pajtas.Csoport != null && csoportok.Contains((int)pajtas.Csoport)))
{
var tanfolyamok = db.TanfolyamHozzaferesek.Where(h => h.IfiAdatlap != null && h.IfiAdatlap == user.Adatlap).Select(tfh => tfh.Tanfolyam).ToList();
var tfosztalyok = db.TanfolyamHozzaferesek.Where(h => h.IfiAdatlap != null && h.IfiAdatlap == user.Adatlap).Select(tfh => tfh.Osztaly).ToList();
if (!(pajtas.TanfolyamOsztaly != null && pajtas.TanfolyamSorszam != null && tanfolyamok.Contains((int)pajtas.TanfolyamSorszam) && tfosztalyok.Contains((TanfolyamOsztaly)pajtas.TanfolyamOsztaly) && tanfolyamok.IndexOf((int)pajtas.TanfolyamSorszam) == tfosztalyok.IndexOf((TanfolyamOsztaly)pajtas.TanfolyamOsztaly)))
{
var tanfvez = db.TanfolyamvezetesHozzaferesek.Where(h => h.IfiAdatlap != null && h.IfiAdatlap == user.Adatlap).Select(tfvh => tfvh.Tanfolyam).ToList();
if (!(pajtas.TanfolyamSorszam != null && tanfvez.Contains((int)pajtas.TanfolyamSorszam)))
{
if (!(User.IsInRole("Nevelo") || User.IsInRole("Admin")))
{
//nincs jogosultság
throw new HttpException((int)System.Net.HttpStatusCode.Forbidden, "Hozzáférés megtagadva");
}
}
}
}
}
But I get an exception at line var csoportok = ...:
System.NotSupportedException: 'Unable to create a constant value of type 'Ifi.Models.Adatlap'. Only primitive types or enumeration types are supported in this context.'
Thanks for any help!

I presume Adaplap is an entity.Change where condition using id instead comparing instances,eg:
.Where(h => h.IfiAdatlap != null && h.IfiAdatlap.Id == user.Adatlap.Id)

The problem is h.IfiAdatlap == user.Adatlap. Because this is a complex type, it won't be accepted, as EF does not know how to do the comparison. You need to compare the ids, something like h.IfiAdatlap.Id == user.Adatlap.Id.

Related

What's the return value of DBSet.Add(object o)

Consider the situation.
I have a userlogin table. the userlogin has the following fields.
userid(identity(1,1)), username(unique), password(string)
I have another table, userRole with following fields.
userid(fk referencing userlogin), role(string)
Now suppose I want to add an admin user to my empty application database.
What I am currently doing is:
// Check Userlogin if it contains adminuser1 as username, if not, add adminuser1 with password xyz.
UserLogin login = new UserLogin();
login.username = "adminuser1";
login.password = "xyz";
context.UserLogins.Add(login);
context.SaveChanges();
// query again from database to get the userid
Userlogin user = context.UserLogins.Single(l => (l.username == "adminuser1") && (l.password == "xyz"));
int userid = user.userid;
UserRole admin = new UserRole();
admin.userid = userid;
admin.role = "admin";
context.UserRoles.Add(admin);
context.SaveChanges();
I want to make it a less troublesome, if we can get the userid of userRecently Added, without making another request.
I mean I want to do this if it is possible.
UserLogin login = new UserLogin();
login.username = "adminuser1";
login.password = "xyz";
UserLogin user = context.UserLogins.Add(login);
UserRole admin = new UserRole();
admin.userid = user.userid;
admin.role = "admin";
context.UserRoles.Add(admin);
context.SaveChanges();
Update
I also wanted to know if there is some way to do
context.UserLogins.Single(l => l == login);
instead of
context.UserLogins.Single(l => (l.username == "adminuser1") && (l.password=="xyz"));
because I use the same method in large classes in many fields.
It can be different based on your needs but you can have something like:
public class UserRole
{
public int Id { get; set; }
public string role { get; set; }
}
public class UserLogin
{
public int Id { get; set; }
public string username { get; set; }
public string password { get; set; }
public UserRole Role { get; set; }
}
and then use them like:
var login = new UserLogin
{
username = "adminuser1",
password = "xyz"
};
var admin = context.UserRoles.Single(_=> _.role == "admin");
if (admin == null)
{
admin = new UserRole
{
role = "admin"
};
}
login.Role = admin;
context.UserLogins.Add(login);
context.SaveChanges();
Your models' relationship seems wrong but based on your information you can have this:
var login = context.UserLogins.Single(_ => _.username == "adminuser1");
if (login == null)
{
login = new UserLogin();
login.username = "adminuser1";
login.password = "xyz";
context.UserLogins.Add(login);
context.SaveChanges();
}
else
{
// this user already exists.
}
var admin = context.UserRoles.Single(_ => _.role == "admin");
if (admin == null)
{
admin.userid = login.userid;
admin.role = "admin";
context.UserRoles.Add(admin);
context.SaveChanges();
}
else
{
// the role already exists.
}
context.UserLogins.Single(l => l == login); would not work for you! you have to query DB based on your model key, not whole model data!
For the question
What's the return value of DBSet.Add(object o)
The answer is: it will return the same object o(i.e. without the userid). Simply because userid is an identity column and relies on the database, its value is only available after context.SaveChanges() is called. Since Add() method only registers that a change will take place after SaveChanges() is called.
For the answer to update,
Instead of using
context.UserLogins.Single(l => (l.username == "adminuser1") && (l.password=="xyz"));
For classes that have many fields, I can check if there are any unique columns. For example. I could use, simply
context.UserLogins.Single(l => l.username == "adminuser1");
Just because, username(unique) is specified in the question.
I would rather recommend people use a single Stored Procedure. The calling of context.SaveChanges() and the context.xyz.Single() require opening database connection multiple times. For optimising performance you can use Stored Procedures, as they require only one connection per task. For more information.
Understang Performance Considerations
As I am using database first approach, I found this link also helpful.
Use Stored Procedure in Entity Framework
Thanks :)

How to check If entry exist in Table? MVC

I am designing something similar to facebook groups. I have user table and Community with one relationship table name CommunityUser. I want to know if the user already joined a community or not? This can take if the communityID exist against that userID in CommunityUser Table.
Here is my IsMember() function code.
public bool IsMember(string UserID, int CommunityID)
{
var MembershipUser = db.Users.Include(x => x.CommunityUsers).Where(s => s.Id == UserID).FirstOrDefault();
var Membership = MembershipUser.CommunityUsers.Count();
if (Membership > 0)
return true;
else
return false;
}
I have virtual connection in my User Table
public virtual ICollection<CommunityUser> CommunityUsers { get; set; }
public ApplicationUser()
{
CommunityUsers = new Collection<CommunityUser>();
}
If you are planning on returning a boolean value, just consider using the Any() method:
public bool IsMember(string UserID, int CommunityID)
{
// This will return if a given user exists
return db.Users.Any(u => u.Id == UserId);
}
Likewise, you could also consider pulling in the related CommunityUsers collection and checking that within your query as well:
public bool IsMember(string UserID, int CommunityID)
{
// This will return true if a given user exists and if a specific
// CommunityId is present for that user
return db.Users.Include("CommunityUsers")
.Any(u => u.Id == UserId && u.CommunityUsers.Any(c => c.Id == CommunityId));
}

How to handle some null entries when populating entity model from multiple linq

I am populating a viewmodel from two queries:
Model:
Student (Name, teacher, HomeroomName, HomeRoomLocation)
The two queries are for the student table, and the Homeroom table. It is possible and ok for the student to not have a homeroom assigned.
var student = context.Student.where(c => c.stuid == studentId).SingleOrDefault();
var homeroom = context.HomeRoom.where(c => c.stuid == studentId).SingleOrDefault();
if(student != null)
{
Student student = new Student
{
Name = student.Name,
Teacher = student.Teacher.Name,
HomeRoomName = homeroom.Name,
HomeRoomLocation = homeroom.Location
};
}
If the homeroom query is null, which is totally fine per the business rules, everything blows up. I could have a bunch of if conditions and return a single model, but I would rather do it in one shot.
Can I do inline ?? in the model population? Like
HomeRoom = homeroom.Name == null ? null : homeroom.Name,
What you need to check is if homeroom variable is null or not:
HomeRoom = homeroom == null ? null : homeroom.Name,
In C# 6.0 you can use Null-Conditional Operator:
HomeRoom = homeroom?.Name,
The null-conditional operator checks whether the operand (in this case homeroom variable) is null prior to invoking the Name property.The logically equivalent explicit code would be the following:
(homeroom!= null) ? homeroom.Name : null
This will allow you to check both variables for null, and create your object, or create a student with no homeroom if the homeroom is null.
if (student != null & homeRoom != null) {
Student student = new Student {
Name = student.Name,
Teacher = student.Teacher.Name,
HomeRoomName = homeroom.Name,
HomeRoomLocation = homeroom.Location
};
} else if (student != null) {
Student student = new Student {
Name = student.Name,
Teacher = student.Teacher.Name
};
}
Why you don't create a constructor inside your Student class?
public Student() {
}
public Student(Student student, HomeRoom homeroom) {
this.Name = student.Name;
this.Teacher = student.Teacher.Name;
if(homeroom != null) {
this.HomeRoomName = homeroom.Name;
this.HomeRoomLocation = homeroom.Location;
}
}
So you can use like this:
var newStudent = new Student(student, homeroom);

Display message with my user id - it will not present it

Right now I am working to create a messaging system to the website, but when I have to pull at it is sent to me and from me, it will not display content on the page.
there mind if I say that it should only take one of them, so accepterer it is perfectly fine.
It's making error here
[HttpGet]
public ActionResult besked(int id)
{
DataLinqDB db = new DataLinqDB();
UnderviserViewModel Model = new UnderviserViewModel();
//Brugerid :)
int userid = Helper.BrugerInformation.SessionVale.SessionBrugerid();
//Det som er blevet sendt til mig!
var ViewBeskederFrom = db.MessageTeachers.Where(i => i.id == id && i.fk_userTo == userid || i.fk_userFrom == userid).ToList();
if (ViewBeskederFrom != null)
{
Model.BeskederFrom = ViewBeskederFrom.ToList();
}
else
{
return RedirectToAction("Indbakke");
}
return View(Model);
}
It works fine if I do it like this.
var ViewBeskederFrom = db.MessageTeachers.Where(i => i.id == id && i.fk_userTo == userid || i.fk_userFrom == userid).ToList();
How can it be that it will not present it if I'm sender or recipient of the message end?
Database here (i have 316 userid)
UPDATE
[HttpGet]
public ActionResult besked(int id)
{
DataLinqDB db = new DataLinqDB();
UnderviserViewModel Model = new UnderviserViewModel();
//Brugerid :)
int userid = Helper.BrugerInformation.SessionVale.SessionBrugerid();
//Det som er blevet sendt til mig!
var ViewBeskederFrom = db.MessageTeachers.FirstOrDefault(i => i.id == id);
if (ViewBeskederFrom != null)
{
List<MessageTeacher> list = db.MessageTeachers.Where(i => i.id == id && i.fk_userTo == userid || i.fk_userFrom == userid).ToList();
if (list != null)
{
Model.BeskederFrom = list.ToList();
}
}
else
{
return RedirectToAction("Indbakke");
}
return View(Model);
}
Because you have an AND condition
i.fk_userTo == userid && i.fk_userFrom == userid
That means you need to have records with both fk_userTo and fk_userFrom column having the same userId value. From your screenshot you do not have such records.
You should be doing the OR condition which will give you either messages you sent or messages sent to you by some other user
i.fk_userTo == userid || i.fk_userFrom == userid
Also, your first if condition( checking the record id value against the id parameter of the action method) is probably going to give you only one record assuming id is the primary key of the table. So the result you are getting in ViewBeskederFrom variable will be List with maximum of one record.

Linq - using multiple variables in a query

I have the following function: -
public IEnumerable<Employee> getEmployees(string department, string searchterm)
{
IEnumerable<Employee> query;
if (department == null || department == ""){
query = from e in db.Employees where e.Date_Leave == null orderby e.EmpSurname select e;
}else{
query = from e in db.Employees where (e.Date_Leave == null) && (e.EmpDept==department) orderby e.EmpSurname select e;
}
return query;
}
At the moment it's just looks at the 'department' variable to determine which query to run but I also want it to look at the 'searchTerm' variable which I will use against the 'EmpSurname' column
My question is, is it possible to have just one query that will use 'department' and 'searchTerm' if they are not null and disregard them if they are null. It could also be that one is null and the other is not.
Thank you
You can compose your query in multiple steps, and it will not be executed until results are actually requested:
public IEnumerable<Employee> getEmployees(string department, string searchterm)
{
IQueryable<Employee> query = db.Employees.Where(e => e.Data_Leave == null);
if (department != null && department != "") {
query = query.Where(e => e.EmpDept == department);
}
if(searchterm != null && searchterm != "") {
query = query.Where(e => e.EmpSurname == searchterm);
}
return query.OrderBy(e => e.EmpSurname);
}
You can use:
var query = from e in db.Employees
where e.Date_Leave == null &&
(department == null || e.EmpDept == department) &&
(searchTerm == null || /* something using searchTerm */)
orderby e.EmpSurname
select e;
Or just conditionally add the queries as Marcin showed. Either approach should be fine.

Resources