Selecting Data from User Input with Entity Framework - c#

I have a form containing some CheckedListBoxes as seen here:
I am able to drill down my data from the first two columns via:
var take = await cmax.dbases.Where(w => statuses.Any(a => w.statusname == a)
&& portfolios.Any(a => w.portfolio == a)).Take(Math.Min((int) takeAmount, count - taken)).ToListAsync();
I would like to then be able to Select() specific data based on my selection in the 2nd two CheckedListBoxes, however, the only method I know to Select Data with EntityFramework is:
Select(s => new { s.ColumnNameHere, s.OtherColumnNameHere });
How may I select the specific properties(columns) based on the user input?

You may want to use DynamicLinq
With it it's possible to write select statements like that (example from site above):
var query = db.Customers.Select("new (CompanyName as Name, Phone)");
So you need to create a string a list of fields and concatenated them or something else.

Related

Retrieve SubItem from a "ToList();" in Lambda

I have a list of users that i get from my database using a Lambda expression. The code should look like this:
var items = db.User.Where(x => x.User_id < 10).ToList();
But this complement "ToList();" wont let me get to the subitems when i try to invoke them with
items.User_Name
Only when i use the .FirstOrDefault(); suffix.
There's anyway to create a list of elements with lambda and still be able to reach it's subitems?
Items variable is a List. List does not have property named User_Name.
If you want to get a User_Name of single item, you can use .FirstOrDefault(); as you mentioned or access items by index like this:
Console.WriteLine(items[1234].User_Name)
If you want to get a list of User_Names you can use Select when you read your data:
db.User.Where(x => x.User_id < 10).Select(x => x.User_Name).ToList();
This way you get a list of user names.
You can read more about Lists in msdn docs. More about Select also in msdn docs.
Yes, you cannot get a User_Name from a list of Users. You can either get a User_Name from a specific User object in that list, e.g. via items.FirstOrDefault().User_Name; like you mentioned gets you the first User in the list and returns their User_Name. Or you could do items[2].User_Name to get the 3rd User's User_Name from that list.
Or if what you mean by "sub items" is that you want a list of just User_Names, then you need the select statement:
var userNames = db.User.Where(x => x.User_id < 10).Select(x => x.User_Name).ToList();

Check if text contains any string item from list of string c# linq

I am trying to fetch a list of users after filtering by their name.
Query:
string filter="alex, faheem, Cohen";
var filterArr=filter.Split(new []{','},StringSplitOptions.RemoveEmptyEntries).Select(f=>f.Trim()).ToList();
var users= (from u in DbContext.Users
where filterArr.Any(y=> u.Name.Contains(y)) select u);
This gives me the error:
Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator.
I can't use filterArr.Contains(x.Name) because Name column contains both first name and second name. Just Like in list above their is an item "alex" and I have a name "Alex Hales" combined in Name column. So If I use filterArr.Contains(x.Name) it will not give me the result.
Any help will be much appreciated.
I'm not sure this is possible in a single statement like this. It's too complicated for the poor parsing stuff to work out.
However, you can get an IQueryable(), then iterate over your filters append these as individual WHERE clauses, then these should get added to the SQL properly later.
Something like this:
//this just gets a reference the DbSet, which implements IQueryable<User>
var queryable = _dbContext.Users;
//iterate over the filters and add each as a separate WHERE clause
foreach(var f in filters)
{
//this just adds to the existing expression tree..
queryable = queryable.Where(u=>u.Name.Contains(f));
}
//this will actually hit the database.
var results = queryable.ToList();
This should generate something like this in SQL (entirely pseudo-code)
select
u.*
from
users u
where
(u.username like "%Sue%")
or (u.username like "%Bob%")
Hope this helps...
I think you can do something like this
string filter = "alex, faheem, Cohen";
var filterArr = filter.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(f => f.Trim()).ToList();
var users = _dbContext.Users.Where(x => filterArr.Any(n => n.Contains(x.Name))).ToList();
UPDATE
For your requirement following query will work fine.
string filter = "Alex, faheem, Cohen";
var filterArr = filter.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Select(f => f.Trim())
.ToList();
var users = _dbContext.Users
.Where(x => filterArr.Any(n => x.UserName.Contains(n))).ToList();
If user has searched for "alex" and in Name (database column) there is "Alex Hales". users query will return the user "Alex Hales".

ASP.NET MVC C# Select and Where Statements

I'm having trouble understanding .Select and .Where statements. What I want to do is select a specific column with "where" criteria based on another column.
For example, what I have is this:
var engineers = db.engineers;
var managers = db.ManagersToEngineers;
List<ManagerToEngineer> matchedManager = null;
Engineer matchedEngineer = null;
if (this.User.Identity.IsAuthenticated)
{
var userEmail = this.User.Identity.Name;
matchedEngineer = engineers.Where(x => x.email == userEmail).FirstOrDefault();
matchedManager = managers.Select(x => x.ManagerId).Where(x => x.EngineerId == matchedEngineer.PersonId).ToList();
}
if (matchedEngineer != null)
{
ViewBag.EngineerId = new SelectList(new List<Engineer> { matchedEngineer }, "PersonId", "FullName");
ViewBag.ManagerId = new SelectList(matchedManager, "PersonId", "FullName");
}
What I'm trying to do above is select from a table that matches Managers to Engineers and select a list of managers based on the engineer's id. This isn't working and when I go like:
matchedManager = managers.Where(x => x.EngineerId == matchedEngineer.PersonId).ToList();
I don't get any errors but I'm not selecting the right column. In fact the moment I'm not sure what I'm selecting. Plus I get the error:
Non-static method requires a target.
if you want to to select the manager, then you need to use FirstOrDefault() as you used one line above, but if it is expected to have multiple managers returned, then you will need List<Manager>, try like:
Update:
so matchedManager is already List<T>, in the case it should be like:
matchedManager = managers.Where(x => x.EngineerId == matchedEngineer.PersonId).ToList();
when you put Select(x=>x.ManagerId) after the Where() now it will return Collection of int not Collection of that type, and as Where() is self descriptive, it filters the collection as in sql, and Select() projects the collection on the column you specify:
List<int> managerIds = managers.Where(x => x.EngineerId == matchedEngineer.PersonId)
.Select(x=>x.ManagerId).ToList();
The easiest way to remember what the methods do is to remember that this is being translated to SQL.
A .Where() method will filter the rows returned.
A .Select() method will filter the columns returned.
However, there are a few ways to do that with the way you should have your objects set up.
First, you could get the Engineer, and access its Managers:
var engineer = context.Engineers.Find(engineerId);
return engineer.Managers;
However, that will first pull the Engineer out of the database, and then go back for all of the Managers. The other way would be to go directly through the Managers.
return context.Managers.Where(manager => manager.EngineerId == engineerId).ToList();
Although, by the look of the code in your question, you may have a cross-reference table (many to many relationship) between Managers and Engineers. In that case, my second example probably wouldn't work. In that case, I would use the first example.
You want to filter data by matching person Id and then selecting manager Id, you need to do following:
matchedManager = managers.Where(x => x.EngineerId == matchedEngineer.PersonId).Select(x => x.ManagerId).ToList();
In your case, you are selecting the ManagerId first and so you have list of ints, instead of managers from which you can filter data
Update:
You also need to check matchedEngineer is not null before retrieving the associated manager. This might be cause of your error
You use "Select" lambda expression to get the field you want, you use "where" to filter results

Need to Include() related entities but no option to do so

I'm not sure how else to word the title of this question so let me explain.
I have a need to select most of one entity type from my database, using .Include to select it's related entities, but at the same time to only select the entities where the entity identifier is equal to one of the IDs in a string array.
My code as follows:
List<TSRCategory> electives = new List<TSRCategory>();
foreach (var i in client.Electives.Split('&'))
{
int id = Int32.Parse(i);
electives.Add(db.TSRCategories.Find(id));
}
This correctly selects the TSRCategories that are part of the Electives list of IDs, but does not include the related entities. I was using this code:
TSRCategories = db.TSRCategories.Include("Competencies.CompetencySkills").ToList();
but this does not select only the chosen Electives. What I am ideally looking for is something like this:
List<TSRCategory> electives = new List<TSRCategory>();
foreach (var i in client.Electives.Split('&'))
{
int id = Int32.Parse(i);
electives.Add(db.TSRCategories.Find(id));
}
TSRCategories = electives.Include("Competencies.CompetencySkills").ToList();
But of course this can't be done for whatever reason (I don't actually know what to search for online in terms of why this can't be done!). Electives is a string with the & as a delimiter to separate the IDs into an array. TSRCategories contains Competencies which contains CompetencySkills. Is there a way to actually do this efficiently and in few lines?
You will find that fetching the associated ids one by one will result in poor query performance. You can fetch them all in one go by first projecting a list of all the needed ids (I've assumed the key name ElectiveId here):
var electiveIds = client.Electives.Split('&')
.Select(i => Int32.Parse(i))
.ToArray();
var electives = db.TSRCategories
.Include(t => t.Competencies.Select(c => c.CompetencySkills))
.Where(tsr => electiveIds.Contains(tsr.ElectiveId))
.ToList();
But one thing to mention is that the storage of your ids in a single string field joined by a delimiter violates database normalization. Instead, you should create a new junction table, e.g. ClientElectives which link the Electives associated with a Client in normalized fashion (ClientId, ElectiveId). This will also simplify your EF retrieval code.
Edit
According to the examples in the documentation, I should be using .Select for depth specification of the eager loading (not .SelectMany or other extension methods).
Try to use this extensions method:
using System.Data.Entity;
from x in db.Z.Include(x => x.Competencies)
.Include(x => x.Competencies.CompetencySkills)
select a.b.c;
To search by the given list of ids:
int[] ids = new int[0]; // or List<int>
from x in db.Z
where ids.Contains(x.Id)
select a.b.c;

Most efficient way to query a database and then remove entries from returned items

I have a app that allows you to follow peoples blog updates. I have a page where the user can choose who to follow. the people who can be followed are stored in a db ( Table name - Person) and when the user selects someone to follow that is also stored in the db ( Table name - Following).
The problem I have is when the user revisits the page to follow another person, what is the best way to query the database and only display people that the user is not following.
I am using Entity framework.
I have the following working. I need a where statement. followBloggers is returning a list of bloggers that the user is following and Uow.People.GetPeople() is returning all bloggers.
var followedBloggers = Uow.FollowBlogger.GetLinks(companyId).ToList();
return Uow.People.GetPeople().Select(p => new { p });
You could use something like this:
var AlreadyFollowed = currentUser.followBloggers.Select( f => f.Id);
Uow.People.GetPeople().Where( p => !AlreadyFollowed.Contains(p.Id));
Try this (assuming that Following has a FK to People on PersonID):
var followedIDs = user.followBloggers.Select(follow => follow.PersonID);
return Uow.People.GetPeople().Where(p => !followedIDs.Contains(p.PersonID));

Categories