Select Multi fields in Entity framework in c# - c#

I want to select 2 or more fields like this: for example we have a list of some people and now they say find people who is male and live in New York
we have 2 fields in here "City" and "Sexual".
I can do it like this
private List<tblTest> GetAll(string city, string sexual)
{
var all = (from x in db.tblTest
where x.city == city && x.sexual == sexual
select x).ToList();
return all;
}
and this one is not helping:
private List<tblTest> GetAll(string city, string sexual)
{
var all = (from x in db.tblTest
where x.city == city || x.sexual == sexual
select x).ToList();
return all;
}
with "&&" I can do it but if I want to just select "City" it is not working, and I want to search like this for 14 fields and we want to search for some fields not all fields we have and we don't know which fields we want to search
What should I do?

The way I do is following:
private List<tblTest> GetAll(string city, string sexual)
{
var query = db.tblTest.AsQueryable();
if(!string.IsNullOrEmpty(city))
{
query = query.Where(x => x.city == city);
}
if(!string.IsNullOrEmpty(sexual ))
{
query = query.Where(x => x.sexual == sexual );
}
return all.ToList();
}
It is important to call AsQueryable otherwise it might be that, if you write IEnumerable<tblTest> query = ..., the result is queried more that 1 times.

Related

C# LINQ Filter records in child tables

I have a main table "SALES" and two secondary tables "PRODUCTS" and "SERVICES", I need to select only the records in "SALES" that contain some product or service entered by the user, I don't need to bring the sales records and products, just filter. First I made the filter in the table "SALES" by date of sale:
var query = (from p in _contexto.sales
where p.datesale.Value.Date >= Convert.ToDateTime(strDtI).Date &&
p.datesale.Value.Date <= Convert.ToDateTime(strDtF).Date
select p);
Now let's say the user wants to filter also the sales that have products or services with the words in a string Array
words = ['apple', 'beef', 'cleaning', 'haircut']
if you receive the array of words, I tried the filter below, but it didn't work, it kept bringing all the records.
var queryi = (from i in _contexto.products
where words.Contains(i.name) || words.Contains(i.description) select i);
//var queryj = (from i in _contexto.services
//where words.Contains(i.name) || words.Contains(i.description) select i);
//query = query.Where(p => queryi.All(c => c.idsale != p.id) || queryj.All(c => c.idsale != p.id));
query = query.Where(p => queryi.All(c => c.idsale != p.id));
where am I failing, and is there a better and more performant way to do this?
Thank you!
Using more descriptive variable names, and assuming you meant to only find products that have the exact same name or description as one of the words, you would have:
var salesInPeriod = from s in _contexto.sales
where Convert.ToDateTime(strDtI).Date <= s.datesale.Value.Date &&
s.datesale.Value.Date <= Convert.ToDateTime(strDtF).Date
select s;
var matchingidsales = from p in _contexto.products
where words.Contains(p.name) || words.Contains(p.description)
select p.idsale;
var ans = from s in salesInPeriod
where matchingidsales.Contains(s.id)
select s;
PS: I inverted the date comparison since I think it makes it easier to see you are doing a between test.

How do I select rows from database elegantly with multiple conditions (which could be null)?

I would like to select data from database according to what the user has entered. However, if that condition is not provided (null), it will ignore that condition and only take the provided conditions to filter out the relevant rows.
I find my solution (pseudocode) to be very inefficient and ugly and I hope someone can share his/her knowledge with me.
This is what I have tried:
'''
//selectConditions - input by user
var dataList = from data in entities.StudentsData
orderby data.Id
select data;
if (selectCondition.Age != null)
{
dataList = filter(dataList, selectCondition.Age);
}
if (selectCondition.Gender != null)
{
dataList = filter(dataList, selectCondition.Gender);
}
//may contain more conditions
//dataList now contains all rows with conditions specified by user
'''
So If I have a table
Name Age Gender
Tom 12 Male
Mary 13 Female
May 15 Female
Jack 14 Male
Case 1: Conditions are
Gender: Male
Age: null
I should get
Tom 12 Male
Jack 14 Male
Case 2: Conditions are
Gender: Female
Age: 15
I should get
May 15 Female
You can use the power of ||
entitieslist.Where(stud =>
(!selectCondition.Age.HasValue || selectCondition.Age == stud.Age)
&& (!selectCondition.Gender.HasValue || selectCondition.Gender== stud.Gender)
.ToList()
I don't think you can apply all filters in a single query. You can check for values that are not null and add appropriate where clauses.
A sample given below:
var datalist = entities.StudentsData.OrderBy(stud => stud.id);
//filterCondition contains the filter values
if(filterCondition.Age.HasValue)
{
datalist = datalist.Where(stud => stud.Age == filterCondition.Age);
}
if(filterCondition.Gender.HasValue)
{
datalist = datalist.Where(stud =>
stud.Gender.Equals(filterCondition.Gender))
}
//More filters can be added as per your requirement.
datalist.ToList();
I hope this will help you.
You can return true if the condition was null
var dataList = from data in entities.StudentsData
where
(selectCondition.Age == null ? true :data.Age ==selectCondition.Age )&&
(selectCondition.Gender == null ? true :data.Gender ==selectCondition.Gender )
//...(check if is null ? return true: your conidtion)
orderby data.Id
select data;
I have done this several ways
One similar, with an IQueryable List, like this
public List<Product1> GetProducts(long? cId, string productCode)
{
var age = false; //Added in a hurry
var gender = "M"; //Added in a hurry
var products =
_unitOfWork.StagingProductRepository.GetMany(
x => x.CID == cId && x.ProductCode == productCode );
if(age)
{
products = products.Where(x => x.ProductAge == age);
}
if (gender != string.Empty)
{
products = products.Where(x => x.Gender.Trim() == gender.Trim());
}
return products.ToList();
}
Also done the same idea but with Raw sql, appending the And clauses
Lastly, Q for you.
Is your filter method enumerating the data?

selecting properties from other table with Lambda expression

I am less experienced with Lambda expression for .NET and trying to get data from SQL using lambda expression. With below query, I am able to get data back, but do not want to use include to get all properties from other tables.
public IEnumerable<ResourceGroup> GetAllServersByApplication(string application_name, string environment_name, string status)
{
var query = _context.ResourceGroup
.Include(a => a.Application)
.Include(t => t.Type)
.Include(e => e.ServersGroup).ThenInclude(e => e.Environment)
.Include(s => s.ServersGroup).ThenInclude(s => s.Server)
.Include(s => s.ServersGroup).ThenInclude(s => s.Server).ThenInclude(s => s.Status)
.Where(a => a.Application.Name == application_name && a.ServersGroup.Any(s => s.Environment.Name == environment_name && s.Server.Status.Name == status))
.ToList();
return query;
}
Lets take an example of below include statement.
.Include(s => s.ServersGroup).ThenInclude(s => s.Server)
From s.Server, I only want to select Id,ServerName,Status, and IPAddress. These are the properties from Servers class that I created as a model.
What is the easy way to exclude all the includes and only show properties that I am interested in?
Here are my tables and its properties:
Status table:
Id, Name
Application table:
Id, Name
Servers table:
Id, ServerName, Status
Environments table:
Id, Name
ResourceGroup table:
Id, Name, Application_Id, Environment_Id
ServersResourceGroup table:
Id, Server_Id, Resource_Id
UPDATE 1:
var query = _context.ResourceGroup
.SelectMany(rg => rg.ServersGroup
.Select(sg => new
{
ResourceName = rg.Name,
ApplicationName = rg.Application.Name,
ServerName = sg.Server.ServerName,
EnvironmentName = sg.Environment.Name,
Status = sg.Server.Status.Name
})).Where(a => a.ApplicationName == application_name && a.EnvironmentName == environment_name && a.Status == status).ToList();
return query;
And error from red line on query variable:
UPDATE 2:
Here is the query syntax:
var query = from rg in _context.ResourceGroup
let app = rg.Application
from sg in rg.ServersGroup
let env = sg.Environment
let srv = sg.Server
let stat = srv.Status
where app.Name == application_name
&& rg.ServersGroup.Any(s => s.Environment.Name == environment_name
&& s.Server.Status.Name == status)
select new
{
ResourceGroupName = rg.Name,
ApplicationName = app.Name,
ServerName = srv.ServerName,
Alias = srv.Alias,
IPAddress = srv.IPAddress,
Type = rg.Type.Name,
Status = stat.Name
};
return query;
Here is the red line error I get in query variable:
Your help is really appreciated. :)
Thanks,
Ray
With lambda expressions, you can use SelectMany to flatten 1-n associations into a 1 dimensional list (i.e. parent and child properties side-by-side). In your case, judging from the Where clause, I think only ResourceGroup - ServerGroup is 1 - n, so it should be something like:
var query = _context.ResourceGroup
.SelectMany
(
rg => rg.ServersGroup
.Select(sg => new
{
ResourceGroup = rg.Name,
Application = rg.Application.Name,
Server = sg.Server.ServerName,
// etc.
})
)
Of course it's good to know how to use lambda expressions, but there's really no point in using them when query syntax makes for much better comprehensible code.
The equivalent in query syntax is:
var query = from rg in _context.ResourceGroup
let app = rg.Application
from sg in rg.ServersGroup
let env = sg.Environment
let srv = sg.Server
let stat = srv.Status
where app.Name == application_name
&& sg.ServersGroup.Any(s => s.Environment.Name == environment_name
&& s.Server.Status.Name == status)
select new
{
ResourceGroup = rg.Name,
Application = app.Name,
Server = srv.ServerName,
// etc. use any property from rg, app, sg, srv, stat
};
As you see -
n - 1 associations are represented by a let statement (which really only helps here to shorten the references in the select)
1-n associations are represented by the from ... from syntax, which is query syntax for SelectMany.
I didn't change the Where clause in the query syntax. Maybe you can use ...
where app.Name == application_name
&& env.Name == environment_name
&& stat.Name == status)
... but note that this is different. The original where returns all ResourceGroup having at least one ServerGroup meeting the condition (and maybe other groups with different environments and statuses). The other where only returns data with environments and statuses equal to the search parameters.
Don't Include all the related tables, but Select all the fields you need. You might find it easier to make a new class to hold the data.
Sorry if I can't make a real query statement here, but your question doens't specify the fields you need.

Advice regarding LINQ query for filtering collections

I have a List<T> of Customers that contains information like: Name, Product, Note, Booking Date, and UnreadMessage.
My goal is to filter customers using these fields and using AND operator but what's troubling me is when there is a field that is not used for filtering.
For example, an assistant will look for a customer name with a specific product. I could have a LINQ query that will look like this.
var a = Customers.Where(x => x.name.Contains("someone") && x.product.Contains("nike"));
Another example is, it will look for a customer with, with a specific product, with some note
var a = Customers.Where(x => x.name.Contains("someone") && x.product.Contains("nike") && x.note.Contains("some note"));
Another example, it will look for a product and booking date
var a = Customers.Where(x => x.product.Contains("someone") && x.bookingdate=DateTime.Now);
I hope you notice how many differenct queries I will write for this kind of filtering.
Name, product, note, booking date, or unread messages only
name and product
name and note
name and booking date
name and unread messages
product and note
product and booking date
etc etc etc etc
I am writing an Windows tablet application by the way so DataTable and LINQ Dyanmics are not possible where I can just write a string expression.
I am aksing for an advice and help how to solve this kind of filtering.
Why not combine Where?
var result = Customers
.Where(item => (null == name) || item.name.Contains(name))
.Where(item => (null == product) || item.product.Contains(product))
.Where(item => (null == note) || item.note.Contains(note))
...
So if you don't want to filter out by any parameter (name, product, etc.) just set it to null.
You can just build your statement dynamically. if this is linq to sql you will benefit from simpler execution plans with this approach:
public class test
{
public string name;
public string lastname;
}
class Program
{
static void Main(string[] args)
{
var list = new List<test>
{
new test{name = "john", lastname = "smith"}
};
string fname = "aa";
string lname = "sm";
var select = list.Select(c=>c);
if (fname != null)
select = select.Where(c => c.name.Contains(fname));
if (lname != null)
select = select.Where(c => c.lastname.Contains(lname));
var result = select.ToList();
}
}

find property value from List<Postavke>() with linq

I have class "Postavke" and then i store it into
List<Postavke> postavke = new List<Postavke>();
Now i want to find some elemnt (property) from this List. I know "Name", "Surname" and i want to get "Address".
How to get "Adress" if i know "Name" and "Surname". All this are properties in "Postavke" class
whole class
public class Postavke
{
#region Properties
public string Name { get; set; }
public string Surname { get; set; }
public string Address { get; set; }
#endregion
#region Methods
public Postavke(string name, string surname, string address, string oznakaLokacije, string oznakaZapore)
{
Name = ean;
Surname = surname;
Address = address;
}
#endregion
}
You can query postavke for all results that contain the name and surname and put the results into a list. Putting the results into a list I find makes things easier to validate and handle unforseen items as from the looks of it it is possible that duplicate items could appear.
if the results must have all data within the list item then:
List<Postavke> results = new List<Postavke>();
var query1 = from a in postavke
where a.Name == searchName
&& a.Surname == searchSurname
select a;
results.AddRange(query1);
this list will have all the results that contain the exact name and surname.
If you just want the address then you can use:
List<string> results = new List<string>();
var query1 = from a in postavke
where a.Name == searchName
&& a.Surname == searchSurname
select a.Address;
results.AddRange(query1);
this will produce a list of addresses. From here you can then validate the list if you want by doing such things as checking to see how many items in the list there are so you know how you want to handle it etc.
If you want to use just either the name or the surname then you can remove the line that asks for one or the other.
If you end up with duplicates but the results are the same then you can change the line
results.AddRange(query1);
to
results.AddRange(query1.Distinct());
by using the Distinct() method it will sort the query and remove duplicates so the list will not be in the same order as it would if you didn't use it.
If you only wanted one result then it's worth validating it by checking how many items are in the list by using
results.Count
you could if it equals 1 carry on, otherwise throw up a message or some other way you may want to handle it. Other pieces of validation that are good is to set values ToLower() and Trim() during the search as to avoid actually changing the original text.
So taking the last query as an example:
List<string> results = new List<string>();
var query1 = from a in postavke
where a.Name.ToLower().Trim() == searchName.ToLower().Trim()
&& a.Surname.ToLower().Trim() == searchSurname.ToLower().Trim()
select a.Address;
results.AddRange(query1);
you can also filter the query with the where clause after you make the query by doing:
List<string> results = new List<string>();
var query1 = from a in postavke
select a.Address;
query1 = query1.Where(h => h.Name == searchName);
query1 = query1.Where(h => h.Surname == searchSurname);
results.AddRange(query1);
The 2 where clauses were split to show you can perform where clause at different points so you could have where clauses within if statements. you can combine the 2 into:
query1 = query1.Where(h => h.Name == searchName && h.Surname == searchSurname);
Hopefully this helps
This will work if you can be sure there's exactly one match
var address = poatavke.Where(p=>p.Name == name && p.Surname == surname).Single().Address;
If you don't know if there's no matches or exactly one you can do:
var posta = poatavke.Where(p=>p.Name == name && p.Surname == surname).SingleOrDefault()
var address = posta == null ? string.Empty : posta.Address;
if you don't know how many matches there's going to be but always want the first (or are using ET which doesn't understand Single())
var posta = poatavke.Where(p=>p.Name == name && p.Surname == surname).FirstOrDefault()
var address = posta == null ? string.Empty : posta.Address;

Categories

Resources