Where clause on field outside Lambda expression class in Linq - linq

If I were to use the following code to select products into a Class names Products, how would I be able to add a Where clause enabled=true without adding it to the class Products?
List<Products> lp = db.products.Select(product => new Products
{
Name = product.name,
Description = product.description,
Category = product.Category
}).ToList();
Adding .Where(x => x.enabled==true) doesn't work because enabled is not part of the Products class, just part of the products table.

List<Products> lp = db.products
.Where(p => p.enabled)
.Select(product => new Products
{
Name = product.name,
Description = product.description,
Category = product.Category
}).ToList();
Also a good practice advice, I'd name the class in singular form, Product.

I assume that you have tried to filter the products-list instead of the table. So you jst have to prepend the Where. This has also the advantage that you filter in the database instead of in the memory.
List<Products> lp = db.products
.Where(p => p.enabled)
.Select(product => new Products
{
Name = product.name,
Description = product.description,
Category = product.Category
}).ToList();
Side-note: you should follow .NET naming conventions. For example use pascal case properties or class names. A class should normally be singular, if you want multiple of it's type use a List<Product>.

List<Products> lp = db.products
.Where(x => x.enabled==true)
.Select(product => new Products
{
Name = product.name,
Description = product.description,
Category = product.Category
}).ToList();

List<Products> lp = db.products.Where(product => product.enabled).
Select(product => new Products
{
Name = product.name,
Description = product.description,
Category = product.Category
}).ToList();

var filter1 = Enumerable.Range(0, 50).Where(c => c % 2 == 0).Select(c => c).ToList();
Console.WriteLine(filter1[3]);
filter1.Insert(4, 13);
foreach (var v in filter1)
{
Console.WriteLine(v);
}

Related

Is there a cleaner and faster way to order this query in Entity Framework?

I have the following code in my application. It works as I want it but I feel as though there has to be a cleaner way to do this without querying the database and then looping through the code to order the children. Any thoughts on how to do this in a cleaner fashion?
var manufacturers = _Context.Manufacturers.Where(x=>x.IsActive).ToList();
foreach (var manufacturer in manufacturers)
{
manufacturer.Models = manufacturer.Models.OrderBy(m => m.Name).ToList();
foreach (var model in manufacturer.Models)
{
model.Sizes = model.Sizes.Where(m => m.Approved).OrderBy(m => m.SortOrder).ThenBy(m=>m.Size).ToList();
}
}
where Manufacturers, Models, and Sizes are all defined entities and are children of the parent objects.
Try using anonymous types:
var theThingsYouWant = _Context.Manufacturers
.Where(man => man.IsActive)
.Select(man => new
{
Manufacturer = man,
Models = man.Models.OrderBy(m => m.Name),
Sizes = man.Models.SelectMany(m => m.Sizes).Where(s => s.Approved).OrderBy(m => m.SortOrder).ThenBy( m => m.Size),
})
.ToList();

Entity - how to get only one column

Is there any possibility to get only one column from .Where statement? For example - ID.
List<testB> test = db.testB.Where(x => x.UserID == userId).ToList();
Here I get all entites testB.
And I just want to return List<int> with testB.ID instead of List<testB>. How can I do this?
db.testB.Where(x => x.UserID == userId).Select(x => x.ID).ToList();
should return a List<int>
Try using .select like this
var test = db.testB.Where(x => x.UserID == userId)
.Select(a => new {
column = a.column
}).ToList();
this creates an anonymous type class of only on attribute. Try it out.

EF how to invert an object hierarchy

I have a list of Users in a family var foo = someUser.MyFamily();
Each User has a list of Classes public virtual List<Class> Classes {get; set;}
Each Class has a list of Dates public virtual List<Date> Dates {get; set;}
To display what's on this week for the family, I'd like to create a table
date class people...
class people...
date+ class people
So what I really want is to invert this arrangement and have
A list of relevant Dates,
Each Date having a list of Classes,
Each Class having a list of Users (but only users in the family)
I'm stuck figuring out how to say it. I keep thinking it should go something like this
var foo = Users x Classes x Dates as in a join
.GroupBy(x => x.Date)
.Select(x => new { something })
.GroupBy(x => x.Class)
.Select(x => new { something })
etc...
and end up being able to say
foreach (var d in foo)
{
use d.Date
foreach (var c in d.Classes)
{
use c.Class.ClassTime, c.Class.ClassName
foreach (var u in c.Users)
{
use u.FirstName
Thanks for insight.
I GOT IT !!!!!
Thanks to this article I learned how to use SelectMany to flatten a hierarchy http://blogs.interknowlogy.com/2008/10/10/use-linqs-selectmany-method-to-flatten-collections/;
Once I had it flattened it was straightforward to use GroupBy() to rebuild the object hierarchy from Dates -> Meetings -> Users such that
Each Date has a list of Meetings
Each Meeting has a list of Users
var meetingDates = Model.User.MyFamily(true)
.SelectMany(x => x.ClassesIamIn)
.SelectMany(x => x.Class.ClassMeetings, (c, d) => new { Date = d.Date, Meeting = d, c.User })
.GroupBy(x => x.Date)
.Select(x => new
{
Date = x.Key,
Meetings = x.Select(y => new { Meeting = y.Meeting, User = y.User })
.GroupBy(a => a.Meeting)
.Select(a => new
{
Meeting = a.Key,
Users = a.Select(b => b.User)
.OrderBy(d => d.FirstName)
})
.OrderBy(c => c.Meeting.TimeStart.TimeOfDay)
});
Wow this has been a struggle; wow what a relief. The above article was the key. I had known how to use SelectMany() to drill inside lists. The thing I didn't know was the goofy lambda syntax for creating a thing that includes the parent object in it (parent, child) => new { parent child mix }

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

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