0

I have method GetByID in my repository that return generic type:

 public T GetById(object id)
 {
    return this.Entities.Find(id);
 }

I'm going to use OData to filtering data, and for that (when I'm using $expand for single row) I need to something like:

SingleResult.Create(repository.GetByID(id));

But of course I got error, because for SingleResult needs type IQueryable<T>.

How can I implement it?

One bad solution is change my GetByID to:

public IQueryable<T> GetById(object id)
{
    return this.Entities.FirstOrDefault(p => p.ID == (int)id);
}

But I prefer to use T GetById because in my opinion it is more correct.

What type should return GetByID? Could you please advise me what to do?

Roman Marusyk
  • 23,328
  • 24
  • 73
  • 116
  • If SingleResult needs an IQueryable, then you have to return an IQueryable. Otherwise you have to couple your repository to OData. I would say, rip out your repository and deal directly with the context in the controller for simplicity's sake. – moarboilerplate Sep 23 '15 at 20:59
  • @moarboilerplate Thanks. Perhaps is there anything else that can be used instead SingleResult? – Roman Marusyk Sep 23 '15 at 21:18
  • I don't think so. If you are attached to maintaining the abstraction that your repo provides for you, then I would recommend injecting a context factory into your controller's constructor allowing you to mock up a context in testing. – moarboilerplate Sep 24 '15 at 17:30

1 Answers1

2

The IQueryable interface defers the filtering to the caller which can do further filtering before "rendering" the final list (in Entity Framework it means executing the actual query with all the WHERE parameters applied at once).

So SingleResult needs an IQueryable to add any further filtering.

If this.Entities is an EF collection (DBSet), you can use .Where(o => o.Id == id) which will return an IQueryable object.

Your question is more one of design if it is good practice to have the Repository class return an IQueryable. I would say it depends on the general design of your solution and which responsibility you assign to which layer.

By looking at this answer (OData $expand, DTOs, and Entity Framework), if ODataController is expecting a IQueryable return type for [Queryable] methods then it is perfectly fine for the repository to return an IQueryable.

Community
  • 1
  • 1
Vincent
  • 22,366
  • 18
  • 58
  • 61
  • Thanks for your replay. Yes, this.Entities is an EF collection (DBSet) and I try to use .FirstOrDefault but then I have to change return type to IQueryable and this is that I do not want do to. I do not use ODataController. – Roman Marusyk Sep 23 '15 at 21:14
  • @MegaTron I'm pretty sure `DbSet.FirstOrDefault()` returns an instance of TEntity, not an `IQueryable`. However, SingleResult requires an `IQueryable`. So if that's the case, then you need to wrap the result from your repo in an `IQueryable` inside your controller again. With that said I strongly advise not implementing what I just suggested and instead keep things simple by not wrapping your context in a repository. Consider that you wouldn't even have this problem if you were using the context directly in the first place. – moarboilerplate Sep 24 '15 at 17:27
  • My mistake, then Where might me more appropriate if you really need to return an IQueryable. – Vincent Sep 24 '15 at 17:32