Linq - using multiple variables in a query - asp.net-mvc

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.

Related

System.NotSupportedException in Entity Framework (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.

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);

how to handle null value in many to many relationship

I am trying to achieve something like this:
if there is a matching id then filter result according to it otherwise bypass the condition
.Where(x => x.NeighbourhoodId == (id ?? x.NeighbourhoodId)
but i am not getting correct syntax with many to many relationship:
public JsonResult GetPost(int? id, int? tagid)
{
var ret = from data in db.Posts.Include(x => x.Tags)
.Include(x => x.Neighbourhood)
.OrderByDescending(x => x.PostedDate)
.Where(x => x.NeighbourhoodId == (id ?? x.NeighbourhoodId)
&& x.Tags.Any(t => t.TagId == tagid))
.ToList()
select new
{
TagName = string.Join(",", data.Tags.Select(t => t.TagName)),
Message = data.Message,
// and other related stuff
}
here, as u can see,this where clause contains multiple conditions i want to filter post.There will be only one parameter with value. means if id parameter have value then tagid will be null and if tagid is null then id would have some value.
now, i want if there is null value in tagid then still this query should run. right now, its not working becoz in database, there is no post with empty tagid or null .how to do it. any suggestions??
If I understand correctly, you need to build the filter dynamically based on the passed parameters like this
var posts = db.Posts
.Include(x => x.Tags)
.Include(x => x.Neighbourhood)
.OrderByDescending(x => x.PostedDate);
if (id != null)
posts = posts.Where(x => x.NeighbourhoodId == id.Value);
if (tagid != null)
posts = posts.Where(x => x.Tags.Any(t => t.TagId == tagid.Value));
var ret = from data in posts
// ... the rest

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.

How to perform LINQ OrderBy based on a stringname for column

If I had
public ActionResult ListExpenseItems(long id)
{
IQueryable<I_ITEM> expenseItems = er.GetExpenseItems(id);
return PartialView(expenseItems );
}
and the LINQ
public IQueryable<I_ITEM> GetExpenseItems(long id)
{
return from i in db.I_ITEM
where i.ExpenseId == id
orderby i.ExpenseItemId ascending
select i;
}
If I passed a string in as a parameter to the LINQ method, say "ExpenseTitle", how would I do OrderBy i.ExpenseTitle so that orderby always matches the string parameter?
This kind of logic.. but actually correct:
db.I_ITEM.OrderBy(x => (orderBy == 'date') ? x.Date : (orderBy == 'id') ? x.Id : (orderBy == 'cost') ? x.Cost : x.Id);
I think this previous questions might solve your problem
Dynamic LINQ OrderBy
Strongly typed dynamic Linq sorting
or you can use the Dynamic Linq library.

Resources