Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning IEnumerable from Repository using ToList() vs using IList

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 IEnumerableto 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.

like image 493
Cody Avatar asked Jan 30 '14 04:01

Cody


2 Answers

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.
  • your sample does not show valid reasons to call .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).
like image 128
Alexei Levenkov Avatar answered Nov 20 '22 16:11

Alexei Levenkov


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;
like image 39
Sinaesthetic Avatar answered Nov 20 '22 16:11

Sinaesthetic