23

I have a DbContext with several DbSet<T> properties:

public virtual DbSet<A> A { get; set; }
public virtual DbSet<B> B { get; set; }
public virtual DbSet<C> C { get; set; }
...

In certain scenarios I must now be able to retrieve a specific DbSet with the entity name as string (e.g. when the user enters "A", I need to get the Dbset<A>).

In previous EF versions, the following was possible:

var dbset = Context.Set(Type.GetType(A));

Is there a similar way to do so with the current versions of EF core? I've tried several ways to achieve that, but the only way I have it working at the moment is using a rather ugly switch/case and I would like to get rid of that.

I've found several posts with similar issues around here, but all of them relate to early .NET Core versions or EF5 / EF6.

Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
lenniep
  • 679
  • 4
  • 11
  • 27
  • Could this link be relevant for you ? https://www.google.be/url?sa=t&source=web&rct=j&url=https://stackoverflow.com/questions/1196991/get-property-value-from-string-using-reflection-in-c-sharp&ved=0ahUKEwi5jqrv_5jYAhWMPRQKHSRtBygQjjgIJzAA&usg=AOvVaw1pJ5XiGk_2j6QSgiy66Bwg – Antoine Thiry Dec 20 '17 at 16:23
  • 1
    I guess [this](https://github.com/aspnet/EntityFrameworkCore/issues/2586) will be helpful – JohnyL Dec 20 '17 at 17:23
  • Ok, there still isn't such method as you can see from the @JohnyL link. And it's because there isn't non generic `DbSet` class. The questions is though do you really need such method. Because most of the `DbSet` methods are exposed from `DbContext` along with non generic versions (`Attach`, `Add`, `Remove`, `Update`, `Find` etc.), so only taking non generic `IQueryable` by entity type could be a problem. – Ivan Stoev Dec 20 '17 at 18:07
  • Thanks @JohnyL and ivan-stoev, this helped quite a bit. While I understand now better why there is no such method, I still agree with the last comment on GitHub - sometimes it's simply not possible to know the exact entity type during design time. – lenniep Dec 21 '17 at 08:22

1 Answers1

23

Do this to add de extension Set(Type t) method to de dbcontext class.

using Microsoft.EntityFrameworkCore;

namespace ApiWebApplication.Utils
{
    public static class MyExtensions 
    {
        public static IQueryable<object> Set (this DbContext _context, Type t)
        {
            return (IQueryable<object>)_context.GetType().GetMethod("Set").MakeGenericMethod(t).Invoke(_context, null);
        }
    }
}

Example:

    // GET: api/Employees
    [HttpGet]
    public IEnumerable<object> GetEmployees()
    {
        return _context.Set(typeof(Employee));
    }
Esteban Kito
  • 578
  • 5
  • 4
  • 5
    This returns an IQueryable - not a DbSet - how would one add entities to this collection for example? – Darrell Jul 31 '19 at 14:53
  • @Darrell It returns the DbSet. – Shimmy Weitzhandler Aug 11 '19 at 07:57
  • 2
    @ShimmyWeitzhandler how does it return the DbSet if it's being cast to a IQueryable? – JKL May 10 '21 at 12:12
  • 1
    With .net6 this call will throw `AmbiguousMatchException` - any other way to do this with .net6? – Sam Nov 21 '21 at 20:15
  • 4
    @Sam `DbContext.Set` now has more than just one signature, you will need to specify the signature, try something like this: `public static DbSet GetDbSet(this DbContext _context) where T : class =>(DbSet)_context.GetType().GetMethod("Set", types: Type.EmptyTypes).MakeGenericMethod(typeof(T)).Invoke(_context, null);` – Smokovsky Dec 21 '21 at 08:10