LINQ get collection in anonymous type - c#

i have the following LINQ statement:
var query =(from item in _itemRepository.FindAll()
where item.Id == "20649458"
from singelitem in item.ListOfChildren
where singelitem.Property == "singelitem"
from manyitems in item.ListOfChildren
where manyitems.Property == "many"
select new
{
item.Id,
singelitem,
manyitems
});
var result = query.ToList();
Tasks is a collection of objects and the where clause tasks.Property == "something" matches several items in the collection, but when i use a anonymous type in the select, i only get back one item (the first) of the matching results instead of a collection of Tasks. How can i get back all the matching tasks in a collection?
Edit:
What really happends is that i get flat objects, (just like a db result set from a join statement).

When you don't use anonymous type you're dealing with entity class which lazy loads the tasks when you access them. If you want to load tasks with your results try using Include method to eager load children. See How do you construct a LINQ to Entities query to load child objects directly, instead of calling a Reference property or Load()

This is the proper behavior of Linq. In fact what you are expecting is not possible. You are expecting a single item matching item.Id == "123"; and what if more than one? it just creates an anonymous item for each matched item. Just think of changing the first "from" statement with the second one; what would you expect?
Also, there is no relationship between first "from" statement and the second one which makes this query a bit "strange". Why not just splitting the query into 2; and creating a new object with the desired properties?

Related

C# Join two tables using Include. Data comes from a Model

I am very new with C# and need some help. I am working on someone elses code and they are pulling data from a Model. I am trying to join two tables and need to use Include but the error is '==' cannot be applied to Guid and IQueryable. Could someone help with this please. Thanks in advance!
Yes, I am.
.Where() represents your filter. .Select() represents what you want back. If you just want the entities back you don't need a .Select().
If you have an association between menu items and MenuItemProgramData, for example, a MenuItem holds a reference to a MenuItemProgramData then you don't even need the first ID select statement:
return context.DbMenuItems
.Where(x => x.MenItemsProgramData.Plu == plu);
Note: If your context defines DbSet<T> for your various top level entities, you can just use context.Ts rather than .GetItems<T>.
If the relationship exists then this is the preferred approach. Let SQL do the work. The consumer of your method can further .Select() the applicable data, sort it, paginate it, and even append .Include() if you do want to interact with the entire entity graph.
If you don't have a relationship between the menu item and that program data, and know that the # of item IDs from the first query will remain relatively small (say, sub-100) then:
var itemIds = context.DbMenuItemProgramDatas
.Where(x => x.Plu == plu)
.Select(x => x.MenuItemId)
.ToList();
Without the .ToList() you are dealing with an IQueryable which EF would potentially still attempt to translate to SQL statements when later consumed. By using .ToList() it will execute the SQL and populate a List<int>. (Assuming the menu item ID is an int)
To get the IQueryable menu item data rows:
return context.DbMenuItems
.Where(x => itemIds.Contains(x.Id));
And that is it.
Edit: Based on the comment "I want to return a field named ParentId to know if it is empty or not. That's all but I need both tables linked to get that answer."
Additionally, looking back at the original code, the naming of the method is a bit misleading. GetItemProgramDataForSubItems implies returning MenuItemsProgramData rather than MenuItems... However, if ParentId is a property of MenuItem, then the caller of this method can use:
var hasParentId = context.GetItemProgramDataForSubItems(plu)
.Any(x => x.ParentId.HasValue);
If the ParentId is on the MenuItemsProgramData:
var hasParentId = context.GetItemProgramDataForSubItems(plu)
.Any(x => x.MenuItemsProgramData.ParentId.HasValue);
Beyond that, you may want to elaborate on what your entities and relationships look like, and what exactly you aim to accomplish from your method or business logic.

Selecting rows in a DBSet with Entity Framework

I'm trying to get rows based on a WHERE clause in a DbSet object. I have this:
dbContext.Workers
I can get a list like this:
workers = m.Workers.Where(w => w.BranchId == curUser.BranchId).ToList<Worker>();
But as you can see, it returns a List<Worker> and I can't use methods like workers.Find(WorkerId) with it.
Basically, I'm trying to return a DBSet based on some filter I mean I want to use LINQ on a DBSet class. I want this because I need to use workers.Find(WorkerId) also maybe I will need to update this model. So, I will get a list based on where clause, I will change some values and will use dbContext.SaveChanges(). Is that possible?
Thanks
Where(...) returns an IQueryable, which you can manipulate BEFORE the query runs. ToList() will force execution of the query and put the objects into memory. If you want to 'find' an item AFTER the query then you could do something like this with your List:
workers.SingleOrDerfault(x => x.WorkerId == WorkerId);
If you have them all in memory like this, and make changes, then you will persist those changes with a call to .SaveChanges().
However, if you need to apply more filtering to your IQueryable BEFORE the query hits the database, then you'll want to manipulate the IQueryable BEFORE the call to ToList().

problem with navigation properties in entity framework

When I execute this query I can navigate in TypeP property:
var items = from item in context.ProductosBodegas.Include("Product.TypeP")
select item;
But when I execute this query the TypeP Property is null:
var items = from item in context.ProductosBodegas.Include("Product.TypeP")
select item.Product;
Why is this?
Looks like Include only affects the directly returned object :
http://msdn.microsoft.com/en-us/library/bb896272.aspx
Otherwise you can call
item.TypePReference.Load()
But this can (and will) lead to perfornance issues (N+1 select), if used in a loop.
Another option would be to "reverse" your query, assuming relationship between Product and ProductosBodegas is bidirectional :
var items = context.Products
.Include("TypeP")
.Where(p => p.ProductosBodegas.Any( /* include condition here if needed */ ))
As far as I know Entity Framework ignores Includes as soon as you don't want to return full entities but only projections. See for instance the answer here. I am not sure if that is still valid for all types of projections but apparently it is still valid in your situation.
You can workaround this by adding the navigation property you want to have loaded into an anonymous type:
var items = from item in context.ProductosBodegas
select new {
Product = item.Product,
TypeP = item.Product.TypeP
};
(You don't need .Include here anymore.) After executing this query (by using .ToList() for instance) you can project to only the part of the anonymous type you want to have, like so:
var products = items.ToList().Select(x => x.Product);
The elements in this products collection have loaded the TypeP reference property now.
Edit:
Important note: Don't change the order of .ToList and .Select.... While this ...
var products = items.Select(x => x.Product).ToList();
... is also syntactically correct and also returns an enumeration of products, the TypeP reference will NOT be loaded in this case. The query for the anonymous type must be executed at first in the database and the anoynmous type collection loaded into memory. Then you can throw away the part of the anoynmous type you don't want to have by the .Select method.
you should load product first
var items = from item in context.ProductosBodegas.Include("Product").Include("Product.TypeP")
select item;

Entity Framework: Why do navigation properties disappear after a group by?

I retrieve a collection with the following query:
var numbers = _betDetailItem.GetBetDetailItems().Where(betDetailItem => betDetailItem.BetDetail.Bet.DateDrawing == resultToCreate.Date && betDetailItem.BetDetail.Bet.Status == 1).Where(condition);
Right there I'm able to access my navigation properties and navigate through binded info. Note how I actually use them to filter the data.
After I group the results, the navigation properties become null.
var grouped = numbers.GroupBy(p => p.BetDetail.Bet);
//Iterate through the collection created by the Grouping
foreach (IGrouping<Bet, BetDetailItem> group in grouped)
{
var details = group.Key.BetDetails; //This is what doesn't work. BetDetails is a navigation property which was accessible in the previous query.
}
Am I doing something wrong?
You are confusing LINQ to Entities and object operations.
This is LINQ to Entities:
var numbers = _betDetailItem.GetBetDetailItems().Where(betDetailItem => betDetailItem.BetDetail.Bet.DateDrawing == resultToCreate.Date && betDetailItem.BetDetail.Bet.Status == 1).Where(condition);
So is this:
var grouped = numbers.GroupBy(p => p.BetDetail.Bet);
These are object operations:
foreach (IGrouping<Bet, BetDetailItem> group in grouped)
{
var details = group.Key.BetDetails; //This is what doesn't work. BetDetails is a navigation property which was accessible in the previous query.
}
In LINQ to Entities, there is never any need to think about loading related instances. You can always refer to any property of any object. However, at some point, you want to move out of the LINQ to Entities world and into object space, because you want to work with instances of type BetDetail instead of type IQueryable<BetDetail>. This means that the Entity Framework is now required to generate SQL to retrieve data from the database. At that point, it doesn't snow which related instances you will be accessing in your code later on. Nothing in your LINQ to Entities query forces the loading of the related Bet. So unless you do something to cause it to be loaded, like use eager loading, explicit loading, or EF 4 lazy loading, it won't be loaded.
Using lazy loading (e.g., in Entity Framework 4, or in another ORM) will make this code appear to function, but it will be unnecessarily slow, due to the large number of database queries generated. A better solution would be to use eager loading or projection. This way there will be only one DB roundtrip.
Once you do a GroupBy(), you're no longer dealing with your entities -- they have been... well, grouped, so the var in var grouped = ... is now of type IEnumerable<IGrouping<.... As such, the methods available on the items in the grouped collection are the methods of the IGrouping<> interface.
You may want to OrderBy() instead of GroupBy(), depending on your need, or you'll need to iterate on two levels: iterate over each group in grouped, and over each member within each of those.
Once you are inside of a particular IGrouping<>, you should have access to the properties for which you are looking.

Linq Working with DataContext

1) I wish to clarify some doubts on collections.
SampleDBDataContext PersonDB = new SampleDBDataContext("");
Table<Person> p=PersonDB.GetTable<Person>();
IEnumerable<Person> per = PersonDB.GetTable<Person>();
IQueryable<Person> qry = PersonDB.Persons.Select(c => c);
what are the differences between using Table<Person>,IEnumerable<Person>,IQueryable<Person>.Any specific need to choose the particular one?
2) For Adding records Add() method not appears in my IDE,(i.e) PersonDB.Persons.Add().
What is the problem here?
1.
IEnumerable<> is an interface that
applies to any collection whose
members can be enumerated or iterated
over.
IQueryable<> is a LINQ interface
that applies to any collection whose
members can be lazily queried.
(queried without materializing the
result set until its members are
accessed)
Table<> is a class that I've
not used before but "represents a
table for a particular type in the
underlying database."
Which one you choose depends on what your needs are, but IEnumerable<> is the most general, so I would use that in my type declarations if it's sufficient.
2.
To insert a person use InsertOnSubmit():
Person person = new Person() { ... };
PersonDB.Persons.InsertOnSubmit(person);
PersonDB.SubmitChanges();
Table(T) is the class that LINQ to SQL uses for query results from a table; it is also used for properties of the data context, so that you can use the data context properties in your queries. So the code in your post is duplicating some code that LINQ is already doing for you. PersonDB.Persons should always be sufficient for querying persons.
For results, you will likely want a collection, so while IEnumerable and IQueryable are fine, you can also consider using a list:
List<Persons> pers = PersonDB.Persons.Where(p => p.name == aName).ToList();
Note that this is an immediate execution, not a lazy (deferred) execution. ToList() forces immediate query execution.
Table<> is well, a table. It can return IQueryable results and can perform inserts/other database specific operations. It is linked to a DataContext.
IQueryable<> is a list that is well, not a list. Basically IQueryable doesn't actually load any data until you actually request it (late execution). As a result you can perform multiple operations before the whole thing is sent to the database. Think of IQueryable<> as an SQL statement in progress, rather then the actual results.
IEnumerable<> is just a standard interface for any list of objects that can be enumerated. When an IQueryable actually executes, you get an IEnumerable set to go through.
Add appears for indvidual instances - for example Person.Add(). For raw tables you should use the Insert* methods.

Categories