17

Say I have a DbContext with the following DbSets

class Amimals : DbContext
{
    public DbSet<Dog> Dogs { get; set; }
    public DbSet<Cat> Cats { get; set; }
}

Inside of each EntityTypeConfiguration I am defining the table for each DbSet like

class DogConfig : EntityTypeConfiguration
{
    public DogConfig()
    {
        this.ToTable("DOG_TABLE");
        ...
    }
}

Now, if I have the table name and the DbContext, how can I grab and use the correct DbSet?

void foo()
{
    string tableName = this.GetTableName();
    using(Animals context = new Animals())
    {
        /* Made up solution */
        DbSet animalContext = context.Where(c => c.TableName == tableName);
        ...
        /* Do something with DbSet */
        ...
    }
}
live2
  • 3,771
  • 2
  • 37
  • 46
DobleA
  • 334
  • 1
  • 3
  • 13
  • For .NET Core refer to this question/answer: [How do I fix `System.MissingMethodException: Constructor on type Microsoft.EntityFrameworkCore.DbSet1 not found`.?](https://stackoverflow.com/questions/76805286/how-do-i-fix-system-missingmethodexception-constructor-on-type-microsoft-entit/) – Tyson Gibby Aug 03 '23 at 14:28

3 Answers3

25

You can get DbSet from DbContext by Type using the method DbContext.Set(Type entityType). So if you have the model class name as string you should do some mapping to actual clr type.

For example:

string tableName = "Cat";
var type = Assembly.GetExecutingAssembly()
        .GetTypes()
        .FirstOrDefault(t => t.Name == tableName);

DbSet catContent;
if(type != null)
    catContent = context.Set(type);

You also can get type from string using Full Assembly Qualified Name Type.GetType(' ... ')

If will be even easier if you can store configurations somehow in generic way and use the generic context.Set<T>() method.

Tyson Gibby
  • 2,590
  • 2
  • 18
  • 37
Viktor Bahtev
  • 4,858
  • 2
  • 31
  • 40
  • Well, this is returning the EntityTypeConfiguration class. I need to use the DbSet. Is there a way to get the instance of the DbSet inside the context? – DobleA Oct 10 '14 at 22:28
  • 1
    Yes, you can. This code works just fine and returns an instance of DbSet. In my example 'talbeName' must match the model class name. Please note that 'tableName' is equal to "Cat" so the result will be DbSet. Ok, 'tableName' sounds somehow unclear it should be 'c# model class name which is used in DbContext generic DbSet with this type and represents some table name'. Please share your not working code. – Viktor Bahtev Oct 11 '14 at 06:46
  • 1
    Well, I can't call Linq methods to the DbSet like I could if I said `context.Cats.Select(c => c)` I tried using `AsQueryable()` but that still doesn't do it – DobleA Oct 13 '14 at 14:21
  • 1
    http://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext.set(v=vs.113).aspx says that `context.Set(type)` returns a non-generic DbSet instance. If I type `context.Set()` I can actually call linq methods for the returned DbSet. Is there a way I can use the `<>` way? – DobleA Oct 13 '14 at 14:31
  • Have you tried Casting the result to a DBSet on the generic? Not sure if it would work without some basic testing. – Dockstar May 01 '17 at 17:58
  • @Dobela Could please share to us that have you got resualt in use `<>` ? I have this problem too – Ali Jun 17 '17 at 05:17
  • 7
    Side note: while this approach works fine on Entity Framework, it's not working on **Entity Framework Core**, though. **For EF Core** I found [this approach](https://stackoverflow.com/a/51958834/9653205) very useful. Hope someone else can find this comment useful as well! – Deadpool Sep 19 '18 at 15:57
2

Another approach is below and work fine for me:

Type t = Type.GetType(Assembly.GetExecutingAssembly().GetName().Name + "." + "TableName");
DbSet dbset = dbcontext.Set(t);
Ali
  • 3,373
  • 5
  • 42
  • 54
  • Error CS0411: The type arguments for method 'method' cannot be inferred from the usage. Try specifying the type arguments explicitly. – Amir978 Jun 22 '21 at 01:18
  • @Amir978 You are using `Entity Framework Core (EF Core)`. The question is about `Entity Framework` (probably EF 6). – Bamdad Jul 05 '21 at 08:44
0

In DotNetCore I did something like this. In this case it would probably be good to use a whitelist to make sure someone doesn't ask for an undesirable entity.

    [HttpGet]
    [Route("entities/{entityName}")]
    public IActionResult GetEntities(string entityName)
    {
        var name = Assembly.GetExecutingAssembly().GetName().Name + ".path.to.your.entity." + entityName;
        Type entityType = Type.GetType(name);
        var results = _myContext
            .GetType()
            .GetMethod("Set")
            .MakeGenericMethod(entityType)
            .Invoke(_myContext, null);
        return Ok(results);
    }
Matt
  • 1,328
  • 1
  • 16
  • 28
  • Thanks for your answer, I tried it but entityType is Null, so the next line throws the error: System.Reflection.AmbiguousMatchException Ambiguous match found – Amir978 Jun 22 '21 at 01:14
  • @Amir978 Just guessing, but you might have two class with the same name in a different space. – Matt Jun 30 '21 at 15:38
  • @Amir978 No the issue is because there are two Set methods. Set() and Set(string) What worked for me was querying for: ...GetMethods().First(e => e.Name == "Set" && e.IsGenericMethod) – Michael Mairegger Sep 06 '21 at 06:55