How to use Linq Contains()? - c#

I am using nHibernate and I need to create a query that does this:
Course Table
CourseId
CourseName
Task Table // course can have many tasks
TaskName
TaskId
CousreId
Now I need to do a contains:
session
.Query<Course>()
.Where(x =>
x.Tasks.Contains(/* wants a task object. I want to do it on property level. */) &&
x.CourseId == 1)
How can I change my query to do a Contains on TaskName?

Project your Tasks to a TaskName then use contains on that.
var query = session
.Query<Course>()
.Where(x => x.Tasks
.Select(t => t.TaskName)
.Contains(myTaskName)
&& x.CourseId == 1);

If I correctly understood you can use Any method
session.Query<Course>().Where(x => x.Tasks.Any(t => t.Name == "task name")
&& x.CourseId == 1);

Have you tried this?
var results = session.Query<Course>()
.Where(crs => crs.Tasks.Count(tsk => tsk.TaskName == theName) > 0);
This should count the number of tasks with the correct name (specified in theName in my example), and return all courses that have a count value greater than zero, i.e. all courses that contain a task with the specific name.

You either have to implement your own IComparer or IEqualityComparer (as I recall, I may be off) and base it on a specific property of the object. Or use Count() or Find() instead. Here's some pseudo code:
session.Query<Course>().Where(x => x.Tasks.Count(t => t.TaskProperty == "something") > 0 && x.CourseId == 1)

I would try something like this:
var results = session
.Query<Course>()
.Where(crs => crs.Tasks.Any(tsk => tsk.TaskName == theName) && crs.CourseId == 1);

Related

Using two Linq query in a single method

As shown in the below code, the API will hit the database two times to perform two Linq Query. Can't I perform the action which I shown below by hitting the database only once?
var IsMailIdAlreadyExist = _Context.UserProfile.Any(e => e.Email == myModelUserProfile.Email);
var IsUserNameAlreadyExist = _Context.UserProfile.Any(x => x.Username == myModelUserProfile.Username);
In order to make one request to database you could first filter for only relevant values and then check again for specific values in the query result:
var selection = _Context.UserProfile
.Where(e => e.Email == myModelUserProfile.Email || e.Username == myModelUserProfile.Username)
.ToList();
var IsMailIdAlreadyExist = selection.Any(x => x.Email == myModelUserProfile.Email);
var IsUserNameAlreadyExist = selection.Any(x => x.Username == myModelUserProfile.Username);
The .ToList() call here will execute the query on database once and return relevant values
Start with
var matches = _Context
.UserProfile
.Where(e => e.Email == myModelUserProfile.Email)
.Select(e => false)
.Take(1)
.Concat(
_Context
.UserProfile
.Where(x => x.Username == myModelUserProfile.Username)
.Select(e => true)
.Take(1)
).ToList();
This gets enough information to distinguish between the four possibilities (no match, email match, username match, both match) with a single query that doesn't return more than two rows at most, and doesn't retrieve unused information. Hence about as small as such a query can be.
With this done:
bool isMailIdAlreadyExist = matches.Any(m => !m);
bool isUserNameAlreadyExist = matches.LastOrDefault();
It's possible with a little hack, which is grouping by a constant:
var presenceData = _Context.UserProfile.GroupBy(x => 0)
.Select(g => new
{
IsMailIdAlreadyExist = g.Any(x => x.Email == myModelUserProfile.Email),
IsUserNameAlreadyExist = g.Any(x => x.Username == myModelUserProfile.Username),
}).First();
The grouping gives you access to 1 group containing all UserProfiles that you can access as often as you want in one query.
Not that I would recommend it just like that. The code is not self-explanatory and to me it seems a premature optimization.
You can do it all in one line, using ValueTuple and LINQ's .Aggregate() method:
(IsMailIdAlreadyExist, IsUserNameAlreadyExist) = _context.UserProfile.Aggregate((Email:false, Username:false), (n, o) => (n.Email || (o.Email == myModelUserProfile.Email ? true : false), n.Username || (o.Username == myModelUserProfile.Username ? true : false)));

Get complex object using IN equivalent in LINQ

I have a list of type customer. I need to insert all values of the list in the database before checking if a customer with the same customer number exists for that particular client.
For that I am firing a query to get me all customers who are there in the database having customer number equal to ones in the list. The query I am writing is not working, here's the code.
CustomerRepository.Find(x => x.ClientId == clientId)
.Where(x => x.CustomerNumber.Contains(lstCustomersInserted.Select(c => c.CustomerNumber)));
Keep it simple:
var lstCustomerNumbers = lstCustomersInserted.Select(c => c.CustomerNumber);
var res = CustomerRepository.Where(x => x.ClientId == clientId && lstCustomerNumbers.Any(c => c == x.CustomerNumber));
I think you have it backwards. Try reversing the Contains.
Edit: I switched to using the generic predicate Exists instead of Contains based on the comment, so you can match a property.
CustomerRepository.Find(x => x.ClientId == clientId)
.Where(x => lstCustomersInserted.Exists(c => x.CustomerNumber == c.CustomerNumber));
How about an Except?
CustomerRepository.Select(x => x.ClientID)
.Except(lstCustomersInserted.Select(x => x.CustomerID));
This will return the IDs of the objects in the repo that don't exist in your lstCustomersInserted.

filtering results with Entity Framework

another kinda newbie question I guess. I have EF setup and now I want to select some records based on a filter. I have SomeClass with 4 items (all strings to keep things simple, lets call them string1, string2, and so on). Now, in a post I send the filter in an instance of SomeClass, but maybe not all properties are filled in.
So you might end up with string1="something", string2="bla" and string4="bla2". So string 3 = null. Now, how do I setup the query? If i try something like:
var dataset = entities.mydatabase
.Where(x => x.string1 == someclass.string1 && x.string2 == someclass.string2 && x.string3 == someclass.string3 && x.string4 == someclass.string4)
.Select(x => new { x.string1, x.string2, x.string3, x.string4}).ToList();
... I get no results, because string3=null. I could do something with checking all parameters and see if they're set and create the query based on that, but there must be something more elegant than that.
Anyone?
Thanks!
Ronald
The following will return all rows where the someclass.string is null OR equals to x.string.
var dataset = entities.mydatabase
.Where(x => someclass.string1 == null || x.string1 == someclass.string1)
.Where(x => someclass.string2 == null || x.string2 == someclass.string2)
.Where(x => someclass.string3 == null || x.string3 == someclass.string3)
.Where(x => someclass.string4 == null || x.string4 == someclass.string4)
.Select(x => new { x.string1, x.string2, x.string3, x.string4}).ToList();

Linq - Orderby by ID Value

I have the following linq:
objfl = db.tblFl.First(t => t.sp == id && t.ProgID == sPgm);
I like to also order by id but not sure how to do this. I tried a number of different ways but was not successful
As suggested by BrokenGlass, if you want to filter by ProgID, sort by sp and retrieve the first item:
db.tblFl.Where(t => t.ProgID == sPgm)
.OrderBy(t => t.sp)
.First()
Try this
objfl = db.tblFl.Where(t => t.sp == id && t.ProgID == sPgm).OrderBy(t => t.sp);

EF query with conditions from multiple tables

I have a table named "Employees". The employeeId from this table MAY be in another table (a many-to-many join tbale) named "Tasks". The other field in the "Tasks" table is a taskId linked to the "TaskDetails" table. This table includes details such as budgetHours.
Using EF4, how do I write the WHERE statement such that the return is employees assigned to tasks where the budgetHours is > 120 hours?
THe WHERE statement in the following limits rows in the Employees table but now I need to add the conditions on the TaskDetails table.
var assocOrg = Employees.Where(x => x.EmployeeTypeID == 2 && x.DepartmentName == "ABC").Select (x => x.EmployeeID);
Thanks!
If Employees has a navigation property named Tasks, try this:
var assocOrg = Employees.Where(x => x.EmployeeTypeID == 2 &&
x.DepartmentName == "ABC" &&
x.Tasks.Any(t => t.BudgetHours > 120))
.Select (x => x.EmployeeID);
If you table sturcture is as below,
TableName Employee Task TaskDetails
ReferenceKeys EmpID EmpdID/TaskID TaskID/BudgetHours
then use,
Employee.Where(x => x.Task.EmpID == x.EmpID && x.Task.TaskDetails.TaskID == x.Task.TaskID && x.Task.TaskDetails.BudgetHours > 120).select(x => x.EmpID)
Assuming you have a Tasks navigation property on the Employee entity, this should be straightforward:
var assocOrg = Employees.Where(x => x.Tasks.Any(t => t.BudgetHours > 120) && x.DepartmentName == "ABC").Select (x => x.EmployeeID);
Of course, this requires the Tasks property to be resolved at this point, either explicitly, via lazy-loading, or with .Include().
(kudos to #adrift for getting Tasks.Any() right... oops.)

Categories

Resources