Optimized Linq IEnumerable query - linq

I have a query which is enumerating over and over and taking very long to run. Can somebody help me optimized it.
public EmpListItem(IEnumerable<EmployeeTable> Emps)
{
IEnumerable<EmployeeTable> emptable = Emps as EmployeeTable[] ?? Emps.ToArray();
TeamList = emptable.Select(x => x.Surname
.Select(c => new EmployeeListItem(c.EmployeeTables.Where(emptable.Contains)))
.Where(x => x.EmpDtos.Any())
.ToList();
}

Related

I am trying to write a SQL subquery in linq

I am trying to write a subquery in linq here is my SQL script
Select id, name from employee where id in (select dictinct id in salaryEmp)
I have tried several combination but not getting the desired output. I will appreciate any help in this regards
This should do it:
db.employee
.Where(x => salaryEmp.Select(x => x.id).Distinct().Contains(x.id))
.Select(x => new { x.id, x.name });
Or better you can do:
var idList = salaryEmp.Select(x => x.id).Distinct().ToList();
var result = db.employee
.Where(x => idList.Contains(x.id))
.Select(x => new { x.id, x.name });
You didn't say how your context looks like, but it will be something like that:
from e in ctx.employee
where
(from s in ctx.salaryEmp
select s.Id).Distinct().Contains(e.id)
select new { e.Id, e.Name }
or with sub query as method-based query:
from e in ctx.employee
where ctx.salaryEmp.Select(s => s.Id).Distinct().Contains(e.id)
select new { e.Id, e.Name }

Query not projecting for oderby?

How can I add an orderby after the select?
//what I have now
string country_list = string.Join(":", ctx.Countries.Select(a => a.CountryName).ToArray());
return country_list;
//what I want to do, but the orderby doesnt see the projections
string country_list = string.Join(":", ctx.Countries.Select(a => a.CountryName).OrderBy(b => b.StateId).ToArray());
return country_list;
its the projection with b that isnt working
You have to call OrderBy before Select, because after projection the column you're trying to order by is no longer available:
string country_list = string.Join(":", ctx.Countries.OrderBy(b => b.StateId).Select(a => a.CountryName).ToArray());
ctx.Countries.Select(a => new { a.CountryName, a.StateId })
.OrderBy(b => b.StateId)
.ToArray()

How to get list that is the distinct select of other lists (LINQ)?

Sorry about the question, I couldn't build the sentence. Here is what I have,
class Brand{
int ModelId;
string name;
}
class Gallery{
IList<Brand> brands;
...
public BrandList{
get{ return brands; }
}
}
I have a list of Gallery. Like this,
IList<Gallery> galleries;
and each Gallery in galleries have many Brands in it. For example, galleries have 6 Gallery object in it. And each gallery has Brands in it. Like this,
Gallery1.Brandlist => Audi, Ford
Gallery2.BrandList => Mercedes,Volvo
Gallery3.BrandList => Subaru
Gallery4.BrandList => Renault
Gallery5.BrandList => Subaru
Gallery6.BrandList =>
What I am trying to get with LINQ is a list of Brands that are distinct of all above's first brand only(so I won't take Ford and Volvo even they are in the list). A gallery doesn't have to have a Brand in their list. So it might be empty as Gallery6. The Output should be,
{Audi, Mercedes, Subaru, Renault}
I don't know how I can do this with LINQ. I tried SelectMany but all I can do with LINQ is simple (p=>p.Something = (int) something).ToList(). I couldn't figure out how to do it.
Use SelectMany and Distinct:
IEnumerable<string> allUniqueBrands = allGalleries
.SelectMany(g => g.BrandList.Select(b => b.Name)).Distinct();
In query syntax:
IEnumerable<string> allBrands = from gallery in allGalleries
from brand in gallery.BrandList
select brand.Name;
IEnumerable<string> allUniqueBrands = allBrands.Distinct();
Edit: Now i got it, you need only the first brands of each BrandList.
If you want to select the Brand you have to provide a custom IEqualityComparer<Brand> which you can use in Distinct. If you neeed a List<Brand>, just call ToList() at the end.
Here's an IEqualityComparer<Brand> for Distinct (or Union,Intesect,Except etc):
public class BrandComparer : IEqualityComparer<Brand>
{
public bool Equals(Brand x, Brand y)
{
if (x == null || y == null) return false;
return x.Name.Equals(y.Name, StringComparison.OrdinalIgnoreCase);
}
public int GetHashCode(Brand obj)
{
if (obj == null) return int.MinValue;
return obj.Name.GetHashCode();
}
}
and here's the distinct list of all (first) brands:
List<Brand> uniqueFirstBrands = allGalleries
.Where(g => g.BrandList != null && g.BrandList.Any())
.Select(g => g.BrandList.First())
.Distinct(new BrandComparer())
.ToList();
This should work:
var brands = galleries.Where(x => x.BrandList.Any())
.Select(x => x.BrandList.First().Name)
.Distinct();
If you want the result being a collection of Brand objects instead of strings, you could do this:
var brands = galleries.Where(x => x.BrandList.Any())
.GroupBy(x => x.BrandList.First().Name)
.Select(g => g.First().BrandList.First());

Deeper level LINQ query in a lambda expression

I would like to get those employees who have a phone number == "666666" using a LINQ query.
These are the class definitions:
public class Employees
{
public List<Phones> Phones{get;set}
}
public class Phones
{
public string Id{get;set;}
public string Number{get;set;}
}
This is my query (my doubt indicated as ???):
var employees= data.GetEmployees()
.Where(e=> e.Phones ???i need to navigate a level below phones ???)
.Select(e => new Employee()
{
Id=e.Id,
Name=e.Name
});
My problem is I don't know how to go a deeper level in this LINQ expression, because in e=>e... I have access to Phones as an IEnumerable but I would like to navigate to Phone's properties.
The easiest way to do this is to use nested LINQ queries. In this case you should look at the Any method.
var employees= data
.GetEmployees()
.Where(e => e.Phones.Any(p => p.Number == "666666"))
.Select(e => new Employee() {
Id = e.Id,
Name = e.Name
});
The parameter passed to the where method is merely a function that returns true or false for each given element, all methods (including LINQ ones (subject to accessing ref/out params etc)) can still be called within it:
var employees= data.GetEmployees()
.Where(e => e.Phones.Any(p => p.Number == "666666"))
.Select(e => new Employee()
{
Id=e.Id,
Name=e.Name
});
var employees= data.GetEmployees()
.Where(e=> e.Phones.Contains(x=>x.Number == "666666"))
.Select(e => new Employee()
{
Id=e.Id,
Name=e.Name
});

How to dynamically group a list depending on role in asp.net mvc

Here is my scenario: We would like to have a page listing donors, depending on the user viewing the page we would like to group by the donor's giving level, or just their sort name. The twist that is throwing me is that we would like to group the Anonomous Donors and give a count based on the grouping.
In my controller I have
[HttpGet]
public ActionResult Society(string id)
{
var society = _db.ONLINEDR_DONOR_LIST
.Include("ONLINEDR_DONORS")
.Single(s => s.DONOR_LIST_ID == id);
var donors = _db.ONLINEDR_DONORS
.Where(d => d.DONOR_LIST_ID == id)
.OrderBy(d => d.SUBGROUP_SORT)
.ThenBy(d => d.SORT_NAME)
.ToList();
if (User.Identity.Name == "public")
{
//First off, check to make sure the list is viewable.
if (society.PUBLIC_IND == "N")
RedirectToAction("Index", "Home");
donors = _db.ONLINEDR_DONORS
.Where(d => d.DONOR_LIST_ID == id)
.OrderBy(d => d.SORT_NAME)
.ToList();
}
var viewModel = new SocietyDetailViewModel()
{
Society = society,
Donors = donors
};
return View(viewModel);
}
I would like to have something like
donors = _db.ONLINEDR_DONORS
.Where(d => d.DONOR_LIST_ID == id)
.GroupBy(d => d.SORT_NAME)
.ToList();
Which I can pass to my view, and then somehow show in the view
<% if (Model.donor.GroupedByItemCount > 1) { %>
<%: Model.donor.GroupedByItemCount %>
<% } %
(I am still new to asp.net MVC and LINQ so any helpful references to explain what I am doing wrong would be appreciated as well).
Thanks so much.
In the declaration of the donors variable, the compiler can determine the type of donors to be List<Donor>
In the assignment within the desired code, donors must be a List<IGrouping<string, Donor>>
donors cannot simultaneously be both types.
Suppose you have this query:
List<IGrouping<string, Donor>> donors = _db.ONLINEDR_DONORS
.Where(d => d.DONOR_LIST_ID == id)
.GroupBy(d => d.SORT_NAME)
.ToList();
This query is local and gives you the keys:
donors.Select(g => g.Key)
This query is mixed mode. A query is sent to the database for each item in the list to fetch its count. This is a potential performance problem.
donors.Select(g => g.Count())
This behavior is due to the difference between LinqToObjects groupby and sql's groupby.
In sql's groupby, you get the key and the aggregates - no elemeents.
In LinqToObjects, you get the key and the elements of the group - and can compute the aggregates from the elements.
Suppose you have this query:
List<IGrouping<string, Donor>> donors = _db.ONLINEDR_DONORS
.Where(d => d.DONOR_LIST_ID == id)
.ToList()
.GroupBy(d => d.SORT_NAME)
.ToList();
In the above query, the records are first hydrated, and then grouped locally. All queries on the result are local.
This query shapes the result data from IGrouping<string, Donor> to GroupShape. GroupShape is some class you make up that has SortName and Count properties.
donors.Select(g => new GroupShape()
{
SortName = g.Key,
Count = g.Count()
});
Suppose you have this query:
List<GroupShape> donors = _db.ONLINEDR_DONORS
.Where(d => d.DONOR_LIST_ID == id)
.GroupBy(d => d.SORT_NAME)
.Select(g => new {SortName = g.Key, Count = g.Count()})
.ToList()
.Select(x => new GroupShape()
{
SortName = x.SortName,
Count = x.Count
}).ToList();
Here, the grouping and counting are done in the database. Each row is first hydrated into an anonymous instance and then copied into an instance of GroupShape (a class you make up).

Resources