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.
Related
I'm trying to make a SQL Query with LinqToEntities which will be as efficient as possible so I would like to avoid iterating after every record I get in results to get a new corrected collection. I'm trying to create a ready collection to send as a result in API just with this one query.
I'm trying to get a discriminator value though with inherited models.
My models are somewhat like these:
public abstract class DbEntity
{
[NotMapped]
public string DiscriminatorValue
{
get
{
return ObjectContext.GetObjectType(GetType()).Name;
}
}
}
public class Foo : DbEntity {
}
public class Bar: DbEntity {
}
This model will create a table in database which will have a column called Discriminator. To get the discriminator value I used my custom DiscriminatorValue property but it won't work in queries like this:
var events = context.MyTable.Select(t => new {
Discriminator = t.DiscriminatorValue
}).ToList();
This below one will obviously work, but it will be much slower imho:
var events = context.MyTable.ToList().Select(t => new {
Discriminator = t.DiscriminatorValue
}).ToList();
Is it possible to get Discriminator value without having to write my custom SQL query myself (like real sql which I know is possible too).
I have the following models which represent my table relationship.
public class A { List<B> B_List }
public class B { public int amount }
I was wondering if it is possible to get top 5 class A objects order by "amount".
I was hoping there is a way to write an EF query to avoid pulling all A objects from database.
I think #Bilal's answer is close, but may not get you exactly what you want. By the way, you haven't been clear on what you mean by "top 5 A objects order by Amount". Each A object has multiple amounts. Are you wanting the top 5 A objects based on the maximum amount? If so, then try this ...
dbContext.AList
.OrderByDescending(a => a.B_List.Sum(b => b.amount))
.Take(5);
I want to hydrate a collection of entities by passing in a comma delimited list of Ids using EF5 Code First.
I would previously have created a table function in t-sql, passed in the comma delimited list of Ids, I'd then join this table to the target table and return my collection of records.
What is the most performant way of using EF5 Code First to achieve the same?
Update: I want to avoid having the full set of entities in memory first.
Update2: I'd ideally like the order of the entities to match the delimited list.
I'd say to start out by converting the comma delimited list into a List<int> that contains all of the IDs that you would be going for. At that point, using your particular DbContext class you would do the following:
var entities = db.MyEntities.Where(e => myListOfIds.Contains(e.ID)).ToList();
Note: I only put the ToList at the end there because you were talking about hydrating the collection. Otherwise, with IEnumerable, there will be deferred execution of the query, and so it will not populate right away.
You could do it like this, where you restrict the set of Entity objects by checking if their IDs belong to your list of IDs:
// Dummy list of POCO 'entity' objects (i.e. the Code first objects) just for the sake of this snippet
var entities = new List<Entity>();
entities.Add(new Entity() { ID = 1, Title = "Ent1" });
entities.Add(new Entity() { ID = 2, Title = "Ent2" });
entities.Add(new Entity() { ID = 3, Title = "Ent3" });
// List of ids to match
var ids = new List<int>();
ids.Add(1);
ids.Add(2);
// LINQ:
var selected = (from e in entities where ids.Contains(e.ID) select e).ToList();
Just for completeness, this is the dummy class used above:
// POCO (Code first) object
private class Entity
{
public int ID { get; set; }
public string Title { get; set; }
}
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)
I'm trying to put together a ViewModel that will have a list of users and each user will have a list of locations.
The User table and Location table are joined together through another table that holds each respective ID and some other information. This table is essentially a many to many join table.
I've tried a few different viewModel approaches and they we're severely lacking... What would be the best approach for displaying this type of information?
I assume that the issue is that you want to be able to access the collection by either User or Location. One approach could be to use ILookup<> classes. You'd start with the many-to-many collection and produce the lookups like this:
var lookupByUser = userLocations.ToLookup(ul => ul.User);
var lookupByLocation = userLocations.ToLookup(ul => ul.Location);
Update:
Per your description, it seems like you don't really need to have a full many-to-many relationship in your ViewModel. Rather, your ViewModel could have a structure like this:
public class YourViewModel
{
public IEnumerable<UserViewModel> Users { get; set; }
}
public class UserViewModel
{
// User-related stuff
public IEnumerable<LocationViewModel> Locations { get; set; }
}
If you wanted to avoid redundant LocationViewModel objects, you could pre-build a mapping between your Model and ViewModel objects:
var locationViewModels = myLocations.ToDictionary(
loc => loc, loc => CreateLocationViewModel(loc));
And then reuse these objects when populating your page's ViewModel.