Update 3/31/2017
I've learned a few more things since this post, so want to give one important reason to use ToList
when returning from the repository - calling ToList
will (when using IQueryable) execute the translated SQL on the database instead of pulling records into memory and then filtering. I don't believe the implicit cast to IEnumerable or IList does this.
Following some of the tutorials on the MSDN website, I have utilized the generic repository layer in my application. This repository layer is called by my service layer, which is in turn called by the controller.
Looking at the generic repository, the data is fetched and is returned by calling ToList()
. However, the return type of the method is IEnumerable
which means the service layer must accept IEnumerable
and before returning to the controller it must once again call a ToList()
on the IEnumerable
.
Example - Repository:
public IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
return orderBy != null ? orderBy(query).ToList() : query.ToList();
}
Example - Service Layer
public IList<DOC> SearchDocuments(string docInfo)
{
// build the predicate and logic, etc
// grab all the matching documents with the relationships
IEnumerable<DOC> documents = _unitOfWork.DocumentRepository.Get(
predicate,
p => p.OrderBy(d => d.DocInfo),
"DocRelationship, DocRelationship.OtherDocTable");
return documents.ToList();
}
From the reading that I've done, it seems to be best to simply present to the controller a List
of objects that it needs versus an IEnumerable
or IQueryable
.
Therefore, I think it would be better to instead of returning an IEnumerable
to return an IList
instead. Am I missing something here - why did the MSDN team choose IEnumerable
for the design and call ToList
? Where would this be useful?? In my eyes it seems to be inefficient and pointless to do that conversion more than once, especially if dealing with a large set of data.
I apologize in advance if this is not clear or there is already an answer, but I have been searching and reading the other posts IEnumerable vs IQueryable vs IList, but I still do not understand this particular issue.
Return minimal interface that works for your particular case.
Often IEnumerable<T>
is enough and give more flexibility, but if you see yourself need to use .ToList()
often (and for valid reasons) return IList<T>
or even List<T>
.
Notes
IEnumerable<T>
allows much easier lazy evaluation and unit testing (since it is smaller than IList
- so try to stick with it..ToList()
- combining IEnumerable<T>
till you know what exactly you are looking for may even get you better performance (i.e. if after several checks you decide you need just one element but ToList
will force you to fetch 10000).You're fine. The main thing that is happening right now is that the .ToList() in the repo is actually executing the query against the database. But returning that list as IEnumerable, all you're really doing is boxing it so that the result is generic and unalterable. There's some overhead there to unbox later on but since the duty of the repository is to return the REQUESTED data, you should return it like this imo.
I think this is probably what the team was thinking. You asked for this data, so here it is. If you need to do further editing on it, you'll have to enumerate it again in order to make any modifications to that list. There's nothing wrong with that. In fact, it supports SoC.
Typically, my repos return IEnumerable, then if my service layer needs to return something like a dto or viewmodel, I'll use that IEnum to build the new object:
var myEnumerable = _uow.MyJunk.Get(j => j.Stuff.Where(a => a.OtherJunk == something);
var myDtos = myEnumerable.Select(obj => new DtoClass { Foo = obj.Foo, Bar = obj.Bar };
return myDtos;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With