Can Entity Framework sort entities by properties on a related entity? - entity-framework

Suppose I have the following "Foo" and "Bar" entities:
class Foo {
int FooId;
string FooName;
}
class Bar {
int BarId;
Foo RelatedFoo;
string BarName;
}
Let's also suppose that I want "RelatedFoo" to be lazy-loaded by default.
In Entity Framework, is it possible to do a query that returns an enumerable of "Bar" entities where elements are sorted by "bar.RelatedFoo.FooName"?
If so, can this be done in a fixed number of database queries? I would like to avoid doing N+1 queries.
If not, is this possible in another .NET ORM framework?

var bars = _context.Bars.OrderBy(b => b.RealtedFoo.FooName)
You may also want to only bring back those bars that RealtedFoo is not null
var bars = _context.Bars.Where(b => b.RelatedFoo != null).OrderBy(b => b.RealtedFoo.FooName)
Update:
//For EF only
_context.Configuration.LazyLoadingEnabled = false
//If you want to bring back RealtedFoo then include it.
//Otherwise, you can just query for it and not use the Include() extension.
var bars = _context.Bars.Include(b => b.RealtedFoo).Where(b => b.RelatedFoo != null).OrderBy(b => b.RealtedFoo.FooName)

Related

Entity Framework equivalent of NHibernate "subselect fetching"

NHibernate has a fetching strategy called "Subselect Fetching" which is detailed here: https://nhibernate.info/doc/nhibernate-reference/performance.html
TLDR: the idea is when we have an entity like this:
class Foo
{
ICollection<Bar> Bars { get; set; }
}
rather than doing a join, we can retrieve both the Foos and the Bars in separate queries (with the results stitched together by NHibernate). In pseudo code:
SELECT * FROM Foo WHERE Name = 'John'
SELECT * FROM Bar WHERE FooId IN (:idFromFirstQuery)
This is useful in the case that Foo is wide and joining to Bar would retrieve a large amount of data.
Is there an equivalent in Entity Framework?
Answering my own question, this can be achieved like this:
var foos = DbContext.Set<Foo>().Where(x => x.Name == 'John').ToList();
var fooIds = foos.Select(x => x.Id).ToArray();
var bars = DbContext.Set<Bar>().Where(x => foos.Contains(x.FooId)).ToList();
The bars variable is then just thrown away (and Resharper will get annoyed), however by virtue of this all occurring within the same DbContext, the Foos will now have their Bar collections populated.

Entity framework with linq in asp.net mvc 5

I am using linq query to group by element through one table field, guid.
The problem is that I do not know how to retrieve the object on the view.
Here is my code:
public ActionResult Index2()
{
List<Imageupload> lists = db.Imageuploads.ToList();
var a = lists.GroupBy(g => g.guid);
return View(a);
}
Imageupload is a modal class and Imageuploads is a table in the database.
How can I accomplish that?
Try this:
var groupedList = db.Imageuploads
.GroupBy(u => u.guid)
.Select(g=> g.ToList())
.ToList();
Hope this helps

Filtering related entities in entity framework 6

I want to fetch the candidate and the work exp where it is not deleted. I am using repository pattern in my c# app mvc.
Kind of having trouble filtering the record and its related child entities
I have list of candidates which have collection of workexp kind of throws error saying cannot build expression from the body.
I tried putting out anonymous object but error still persist, but if I use a VM or DTO for returning the data the query works.
It's like EF doesn't like newing up of the existing entity within its current context.
var candidate = dbcontext.candidate
.where(c=>c.candiate.ID == id).include(c=>c.WorkExperience)
.select(e=>new candidate
{
WorkExperience = e.WorkExperience.where(k=>k.isdeleted==false).tolist()
});
Is there any workaround for this?
You cannot call ToList in the expression that is traslated to SQL. Alternatively, you can start you query from selecting from WorkExperience table. I'm not aware of the structure of your database, but something like this might work:
var candidate = dbcontext.WorkExperience
.Include(exp => exp.Candidate)
.Where(exp => exp.isdeleted == false && exp.Candidate.ID == id)
.GroupBy(exp => exp.Candidate)
.ToArray() //query actually gets executed and return grouped data from the DB
.Select(groped => new {
Candidate = grouped.Key,
Experience = grouped.ToArray()
});
var candidate =
from(dbcontext.candidate.Include(c=>c.WorkExperience)
where(c=>c.candiate.ID == id)
select c).ToList().Select(cand => new candidate{WorkExperience = cand.WorkExperience.where(k=>k.isdeleted==false).tolist()});

Join 2 different entities from 2 different models into a single Linq to Entities query

I have a default Entity Framework model that holds all of my default tables for my product, and that all customers share in common. However, on some customers, I have some custom tables that exist for only that customer, but they relate to the default product's tables. I have a second Entity Framework model to hold these custom tables.
My question is how can I make a Linq to Entities query using Join so I can relate the entities from my default model to the tables on my custom model? I don't mind not having the Navigation properties from the custom entity to the entities on the default model; I just need a way to query both models in a single query.
Below is the code:
using (ProductEntities oProductDB = new ProductEntities())
{
using (ProductEntitiesCustom oProductCustomDB = new ProductEntitiesCustom())
{
var oConsulta = oProductCustomDB.CTBLCustoms
.Where(CTBLCustoms => CTBLCustoms.IDWOHD >= 12)
.Join(oProductDB.TBLResources,
CTBLCustoms => new
{
CTBLCustoms.IDResource
},
TBLResources => new
{
TBLResources.IDResource
},
(CTBLCustoms, TBLResources) => new
{
IDCustom = CTBLCustoms.IDCustom,
Descricao = CTBLCustoms.Descricao,
IDWOHD = CTBLCustoms.IDWOHD,
IDResource = CTBLCustoms.IDResource,
ResourceCode = TBLResources.Code
});
gvwDados.DataSource = oConsulta;
}
}
I get a The specified LINQ expression contains references to queries that are associated with different contexts error.
EDIT
Could I merge the 2 ObjectContext into a third, and then run the Linq query?
Tks
EDIT
Below is the code that worked, using the AsEnumerable() proposed solution:
using (ProductEntities oProductDB = new ProductEntities())
{
using (ProductEntitiesCustom oProductCustomDB = new ProductEntitiesCustom())
{
var oConsulta = (oProductCustomDB.CTBLCustoms.AsEnumerable()
.Where(CTBLCustoms => CTBLCustoms.IDWOHD >= 12)
.Join(oProductDB.TBLResources,
CTBLCustoms => new
{
CTBLCustoms.IDResource
},
TBLResources => new
{
TBLResources.IDResource
},
(CTBLCustoms, TBLResources) => new
{
IDCustom = CTBLCustoms.IDCustom,
Descricao = CTBLCustoms.Descricao,
IDWOHD = CTBLCustoms.IDWOHD,
IDResource = CTBLCustoms.IDResource,
ResourceCode = TBLResources.Code
})).ToList();
gvwDados.DataSource = oConsulta;
}
}
I added the AsEnumerable() as suggested, but I had to add the ToList() at the end so I could databind it to the DataGridView.
You can't do this in L2E. You could bring this into object space with AsEnumerable(), and it would work, but possibly be inefficient.
Merging the ObjectContexts is possible, and would work, but would need to be done manually.

navigating many-to-many via include in EF4

I have a many to many relationship in EF4 with the following entities:
[Student] - [Class] - [Student_Class]
Moreover i have a [School] entity with a FK on [Student].
If i want to have all the Students of my school i do:
context.School.Include("Student")
but if i want to have the 1rst class of my Students in my school ?
context.School.Include("Student").Include("Student_Class").Where(...
i did not manage to make this thing work...
Can you help ?
Also is it more intelligent to write a full Linq select?
Thanks
John
If you want to do a conditional eager load, then you should NOT be using the Include method.
For loading your school object containing only the students that belong to the first class
You can do a Filtered Projection which returns an Anonymous Type object:
var school = context.School
.Where(s => s.SchoolID == 1) // or any other predicate
.Select(s => new
{
School = s,
Students = s.Student.Where(st => st.ClassID == 1)
}).ToList();
Another way would be to Leverage Attach Method which returns EntityObject:
var school = context.School.Where(s => s.SchoolID == 1).First()
var sourceQuery = school.Students.CreateSourceQuery()
.Where(st => st.ClassID == 1);
school.Students.Attach(sourceQuery);
For a more detailed discussion about this, you can also check:
Entity Framework: How to query data in a Navigation property table