What is the behaviour when returning a query result through a function and then continuing to query on that result?
I am using ASP.NET MVC 3 with Entity Framework 4 using POCOs and want to query a set and select some properties to put into my viewModel. I will sketch a simplified version of my situation:
Situation:
I have an entity BananaTree
containing a collection of Banana
public class Banana
{
public int Id { get; set; }
public int Size { get; set; }
public TimeSpan Age { get; set }
public string Description { get; set; }
}
public class BananaTree
{
public int Id { get; set; }
public ICollection<Banana> Bananas { get; set; }
}
I also have a view model BananaListItemViewModel
used in the view showing a list of bananas for a certain banana tree. This view is managed by the BananaTreeController
public class BananaListItemViewModel
{
public int Id { get; set; }
public TimeSpan Age { get; set }
}
I have a Details action on the controller like so:
public ActionResult Details(int bananaTreeId)
{
var viewModel = from bananaTree in bananaTreeRepository.BananaTrees
where bananaTree.Id == bananaTreeId
from banana in bananaTree.Bananas
select new BananaListItemViewModel
{
Id = banana.Id,
Age = banana.Age
};
return View(viewModel);
}
What I want to change
This works fine and now I only select the items from the database that I need for my view model. However, I want to take out some more logic from my controller and am trying to do this as much as possible.
I would like to have a function in my repository like so:
IQueryable<Banana> GetBananas(int bananaTreeId)
{
return (from bananaTree in BananaTrees
where bananaTree.Id == bananaTreeId
select bananaTree.Bananas).Single().AsQueryable();
}
and use it like so:
public ActionResult Details(int bananaTreeId)
{
var viewModel = from banana in bananaTreeRepository.GetBananas(bananaTreeId)
select new BananaListItemViewModel
{
Id = banana.Id,
Age = banana.Age
};
return View(viewModel);
}
Question
My question is, in this case, will the two queries be combined and go to the database in one go like in my first example or will this first get all the bananas from the tree completely out of the database and perform the second query on that list? I would prefer the first case. If not, could I rewrite the GetBananas
query to get that behaviour (for example like the query below)?
IQueryable<Banana> GetBananas(int bananaTreeId)
{
return from bananaTree in BananaTrees
where bananaTree.Id == bananaTreeId
开发者_如何学Python from banana in bananaTree.Bananas
select banana;
}
Thanks very much in advance.
In your specific case, it will be only one query, if the call to Single()
doesn't lead to the query to be executed. Unfortunately, I couldn't find any info on whether it does or does not. The call to AsQueryable
does not trigger the execution as long, as the Bananas
property really is an IQueryable
.
According to http://msdn.microsoft.com/en-us/library/bb156472.aspx, the call to Single
doesn't execute your query.
Conclusion:
You code should result in only one query.
In general:
You can pass an IQueryable
from one method to another without it being implicitly executed.
The following code will result in only one SQL statement executed at the end, when the call to ToList
happens:
IQueryable<Banana> GetBananasByWeight(int weight)
{
return from banana in Bananas where banana.Weight = weight;
}
IQueryable<Banana> FilterByQuality(IQueryable<Banana> bananaQuery, int quality)
{
return bananaQuery.Where(b => b.Quality == quality);
}
public List<Banana> GetBananas(int weight, int quality)
{
var query = GetBananasByWeight(weight);
var filteredBananas = FilterByQuality(query, quality);
return filteredBananas.ToList();
}
精彩评论