EntityFramework - How to populate child members? - c#

I have been given a model to work with but cannot figure out the LINQ query to get what I need into my object.
Given an initial date, I need to retrieve all of the items posted for sale since then, member details, and the filenames of the photos of those items.
Also need to be able to pass in a MemberID and find which items they have for sale (and filenames)
Can someone please point me to what the query for this would be?
I've been following a few EF tutorials but am having lots of trouble figuring this one out...
When I try this, I get a null reference exception when talking to the photoURL.
var items = db.BuySellLists.Include(b => b.Member)
.Include(b => b.BuySellPhoto)
.Where(b => b.PostedDate >= fromDate && b.IsBuyable == true)
.OrderBy(b => b.PostedDate)
.ToList();
I've currently got it working by looking up all items for sale, then from there looping over each BuySellListId to get that items photos to get the URL, but this causes quite a few individual queries to the database and is giving performance issues.

Photo is not implicitly included in your query. That is why you get a NullReferenceException. You need to include it explicitly as follows:
Include(b => b.BuySellPhoto.Photo)
Check MSDN documentation on Include extension for more details.

Related

How to query based on an previous object result? Entity Framework

I am extremely stuck with getting the right information from the DB. So, basically the problem is that I need to add where closure in my statement to validate that it only retrieves the real and needed information.
public async Task<IEnumerable<Post>> GetAllPosts(int userId, int pageNumber)
{
var followersIds = _dataContext.Followees.Where(f => f.CaUserId == userId).AsQueryable();
pageNumber *= 15;
var posts = await _dataContext.Posts
.Include(p => p.CaUser)
.Include(p => p.CaUser.Photos)
.Include(c => c.Comments)
.Where(u => u.CaUserId == followersIds.Id) <=== ERROR
.Include(l => l.LikeDet).ToListAsync();
return posts.OrderByDescending(p => p.Created).Take(pageNumber);
}
As you can see the followersIds contains all the required Id which I need to validate in the post variable. However I have tried with a foreach but nothing seems to work here. Can somebody help me with this issue?
The short version is that you can change that error line you have marked above to something like .Where(u => followersIds.Contains(u.CaUserId) which will return all entities with an CaUserID that is contained in the followersIds variable, however this still has the potential to return a much larger dataset than you will actually need and be quite a large query. (You also might need to check the sytax just a bit, shooting from memory without an IDE open) You are including a lot of linked entities in that query above, so maybe you'd be better off using a Select query vs a Where query, which would load only the properties that you need from each entity.
Take a look at this article from Jon Smith, who wrote the book "Entity Framework Core In Action", where he talks about using Select queries and DTO's to only get out what you need. Chances are, you don't need every property of every entity you are asking for in the query you have above. (Maybe you do, what do I know :p) Using this might help you get something much more efficient for just the dataset you need. More lines of code in the query, but potentaily better performance on the back end and a lighter memory footprint.

C# Entity Framework Pagination Children Includes

I am looking for the fastest way to do the following operation. What I need to accomplish, is I have a screen that displays the "Parts" that are defined inside of a "Lot". Each part has objects of a station, and each station has objects of tools, and each tool can have measurements.
My problem is I cannot get the pagination to work. The incoming offset is 0, and the number of records to take is 20 however the following operation is not working:
Lot foundLot = EntitiesContext.Lots.Where(x => x.ID == lotID)
.IncludeFilter(lot => lot.Parts.OrderBy(n => n.PartID).Skip(offset).Take(numberOfRecords).ToList())
.IncludeOptimized(lot => lot.Parts.Select(parts => parts.Stations))
.IncludeOptimized(lot => lot.Parts.Select(parts => parts.Stations.Select(station => station.Tools)))
.IncludeOptimized(lot => lot.Parts.Select(parts => parts.Stations.Select(station =>
station.Tools.Select(tools => tools.Measurements))))
.FirstOrDefault();
So I am trying to filter to only grab certain parts, and then of those filtered parts, I want to grab all of the children's data associated with them. I have checked all of the existing stack overflow articles related to this, and the changes I make either result in the Z.EntityFrameworkPlus package throwing a generic exception, that provides no details (which is what the above code does), or if I use the regular EntityFramework functions it throws an exception for the invalid path.
Thank you for your assistance.
Okay, after reading the docs for Z.EntityFrameworkPlus I now see you cannot use IncludeFilter and IncludeOptimzed on the same LINQ statement
https://entityframework-plus.net/query-include-optimized
I switched IncludeFilter to IncludeOptimzed and it works.

LINQ pull records from a database where string list is from a model

I have a database of strings that contain IDs. I need to pass that list into a LINQ query so I can pull the correct records.
model.SelectedDealers = db.dealers.Any(a => a.sdealer_name.Contains(UserToEdit.UserViewAccesses.Select(s => s.ViewReferenceNumber)));
SelectedDealers is of type dealers
ViewReferenceNumber should be a list of strings which should match sdealer_name
So essentially I am trying to find all of the dealers whos sdealer_name matches the list of sdealer_names I have in my UserToEdit.UserViewAccesses
I've tried moving parts around and switching them in different spots and can't seem to figure this out.
Any() is just a boolean indicating if there are any results. It doesn't actually return the results.
If I understand what you are after correctly, then this might work:
var dealerNames = UserToEdit.UserViewAccesses.Select(s => s.ViewReferenceNumber).ToList();
model.SelectedDealers = db.dealers.Where(a => dealerNames.Contains(a.sdealer_name));
So essentially I am trying to find all of the dealers whos
sdealer_name matches the list of sdealer_names I have in my
UserToEdit.UserViewAccesses
var dealersthatmatched = (from d in UserToEdit.UserViewAccesses.sdealer_names
where d == sdealer_name
select d).ToList()
Wish I could have made a comment instead, but as I don't have enough rep I can't. I wish I understood the requirement better, but you seem ready and able to try stuff so perhaps you find this useful.

Select All from Collection Where ID in List

I'm just learning to use lambda expressions and was turned on to Dapper a couple days ago. I'm working on an app that populates a listView with usernames to be selected for some account maintenance. I'm having trouble with one part of sorting:
I'm getting a collection of objects using a Dapper query and assigning it to the variable Global.allUsers.
I have a list of IDs (List<int> migrated) that have already been used, and so don't need to appear in the listView
I'm getting a list of all my users using the following:
var uniqUsers = Global.allUsers.OrderBy(n => n.lastNames).GroupBy(q => q.salesIDs);
To populate the listView with only the users who haven't been migrated, I need to select only those users without q.salesIDs in migrated. I just can't quite figure out if/how I can do this without using some kind of foreach. Seems like there should be a way to select it.
Granted, I'm looping through uniqUsers anyway, and populating the listView with values out of each object's properties. I can add a statement to check if the current ID is in migrated, but my gut is just telling me that I can do it with the select statement and save myself a step.
I'm thinking something like this:
var uniqUsers = Global.allUsers.Where(i => i.salesIDs not in migrated).OrderBy(n => n.lastNames).GroupBy(q => q.salesIDs);
but i => i.salesIDs not in migrated isn't cutting it.
This does what you need:
var uniqUsers = allUsers.Where(x => migrated.Contains(x.salesIDs))
.OrderBy(y => y.lastNames)
.GroupBy(z => z.salesIDs).SelectMany(v => v).ToList();
Gets all users where the salesID is in migrated, then orders by lastNames and then groups by the salesID. The SelectMany() will project the elements to a sequence, the ToList() will enumerate the results.

How do I apply the LINQ to SQL Distinct() operator to a List<T>?

I have a serious(it's getting me crazy) problem with LINQ to SQL. I am developing an ASP.NET MVC3 application using c# and Razor in Visual Studio 2010.
I have two database tables, Product and Categories:
Product(Prod_Id[primary key], other attributes)
Categories((Dept_Id, Prod_Id) [primary keys], other attributes)
Obviously Prod_Id in Categories is a foreign key. Both classes are mapped using the Entity Framework (EF). I do not mention the context of the application for simplicity.
In Categories there are multiple rows containing the Prod_Id. I want to make a projection of all Distinct Prod_Id in Categories. I did it using plain (T)SQL in SQL Server MGMT Studio according to this (really simple) query:
SELECT DISTINCT Prod_Id
FROM Categories
and the result is correct. Now I need to make this query in my application so I used:
var query = _StoreDB.Categories.Select(m => m.Prod_Id).Distinct();
I go to check the result of my query by using:
query.Select(m => m.Prod_Id);
or
foreach(var item in query)
{
item.Prod_Id;
//other instructions
}
and it does not work. First of all the Intellisense when I attempt to write query.Select(m => m. or item.shows just suggestions about methods (such as Equals, etc...) and not properties. I thought that maybe there was something wrong with Intellisense (I guess most of you many times hoped that Intellisense was wrong :-D) but when I launch the application I receive an error at runtime.
Before giving your answer keep in mind that;
I checked many forums, I tried the normal LINQ to SQL (without using lambdas) but it does not work. The fact that it works in (T)SQL means that there is something wrong with the LINQ to SQL instruction (other queries in my application work perfectly).
For application related reasons, I used a List<T> variable instead of _StoreDB.Categories and I thought that was the problem. If you can offer me a solution without using a List<T> is appreciated as well.
This line:
var query = _StoreDB.Categories.Select(m => m.Prod_Id).Distinct();
Your LINQ query most likely returns IEnumerable... of ints (judging by Select(m => m.Prod_Id)). You have list of integers, not list of entity objects. Try to print them and see what you got.
Calling _StoreDB.Categories.Select(m => m.Prod_Id) means that query will contain Prod_Id values only, not the entire entity. It would be roughly equivalent to this SQL, which selects only one column (instead of the entire row):
SELECT Prod_Id FROM Categories;
So when you iterate through query using foreach (var item in query), the type of item is probably int (or whatever your Prod_Id column is), not your entity. That's why Intellisense doesn't show the entity properties that you expect when you type "item."...
If you want all of the columns in Categories to be included in query, you don't even need to use .Select(m => m). You can just do this:
var query = _StoreDB.Categories.Distinct();
Note that if you don't explicitly pass an IEqualityComparer<T> to Distinct(), EqualityComparer<T>.Default will be used (which may or may not behave the way you want it to, depending on the type of T, whether or not it implements System.IEquatable<T>, etc.).
For more info on getting Distinct to work in situations similar to yours, take a look at this question or this question and the related discussions.
As has been explained by the other answers, the error that the OP ran into was because the result of his code was a collection of ints, not a collection of Categories.
What hasn't been answered was his question about how to use the collection of ints in a join or something in order to get at some useful data. I will attempt to do that here.
Now, I'm not really sure why the OP wanted to get a distinct list of Prod_Ids from Categories, rather than just getting the Prod_Ids from Projects. Perhaps he wanted to find out what Products are related to one or more Categories, thus any uncategorized Products would be excluded from the results. I'll assume this is the case and that the desired result is a collection of distinct Products that have associated Categories. I'll first answer the question about what to do with the Prod_Ids first, and then offer some alternatives.
We can take the collection of Prod_Ids exactly as they were created in the question as a query:
var query = _StoreDB.Categories.Select(m => m.Prod_Id).Distinct();
Then we would use join, like so:
var products = query.Join(_StoreDB.Products, id => id, p => p.Prod_Id,
(id,p) => p);
This takes the query, joins it with the Products table, specifies the keys to use, and finally says to return the Product entity from each matching set. Because we know that the Prod_Ids in query are unique (because of Distinct()) and the Prod_Ids in Products are unique (by definition because it is the primary key), we know that the results will be unique without having to call Distinct().
Now, the above will get the desired results, but it's definitely not the cleanest or simplest way to do it. If the Category entities are defined with a relational property that returns the related record from Products (which would likely be called Product), the simplest way to do what we're trying to do would be the following:
var products = _StoreDB.Categories.Select(c => c.Product).Distinct();
This gets the Product from each Category and returns a distinct collection of them.
If the Category entity doesn't have the Product relational property, then we can go back to using the Join function to get our Products.
var products = _StoreDB.Categories.Join(_StoreDB.Products, c => c.Prod_Id,
p => p.Prod_Id, (c,p) => p).Distinct();
Finally, if we aren't just wanting a simple collection of Products, then some more though would have to go into this and perhaps the simplest thing would be to handle that when iterating through the Products. Another example would be for getting a count for the number of Categories each Product belongs to. If that's the case, I would reverse the logic and start with Products, like so:
var productsWithCount = _StoreDB.Products.Select(p => new { Product = p,
NumberOfCategories = _StoreDB.Categories.Count(c => c.Prod_Id == p.Prod_Id)});
This would result in a collection of anonymous typed objects that reference the Product and the NumberOfCategories related to that Product. If we still needed to exclude any uncatorized Products, we could append .Where(r => r.NumberOfCategories > 0) before the semicolon. Of course, if the Product entity is defined with a relational property for the related Categories, you wouldn't need this because you could just take any Product and do the following:
int NumberOfCategories = product.Categories.Count();
Anyway, sorry for rambling on. I hope this proves helpful to anyone else that runs into a similar issue. ;)

Categories