3

I want to make a factory class to return DbContext object where table name will be passed as string. There are more than 100 tables in database, each having a different structure/schema.

The idea is to pass tableName as string in the method which will return object in EF and we can select/update these records. I found this code in some article but have some confusion how to use it:

public ObjectContext Context(EntityObject entity)
{
        var relationshipManager = ((IEntityWithRelationships)entity).RelationshipManager;
        var wrappedOwnerProperty = relationshipManager.GetType().GetProperty("WrappedOwner", BindingFlags.Instance | BindingFlags.NonPublic);
        var wrappedOwner = wrappedOwnerProperty.GetValue(relationshipManager);
        var contextProperty = wrappedOwner.GetType().GetProperty("Context");
        return (ObjectContext)contextProperty.GetValue(wrappedOwner);
}

I am not sure if this is what I need. Also what should I pass in EntityObject entity and where I should pass the tableName?

Please let me know if there is any other way to achieve the same thing.

1 Answer 1

7

One simple way to do this is to use the DbContext.Set() method, and get the type based on the string.

using (var db = new MyDbContext)
{
    string tableName = "ApplicationUser";
    var type = Assembly.GetExecutingAssembly()
       .GetTypes()
       .FirstOrDefault(t => t.Name == tableName);

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

However, this has one drawback and that's that this is a non-generic DbSet (ie it's a DbSet not a DbSet<T>).

A way to get the Generic DbSet (which allows linq functionality) would be to do something like this:

using (var db = new IdentityDbContext())
{
    string tableName = "ApplicationUser";
    var type = Assembly.GetExecutingAssembly()
       .GetTypes().FirstOrDefault(t => t.Name == tableName);

    var method = db.GetType().GetMethods()
       .First(x => x.IsGenericMethod && x.Name == "Set");

    MethodInfo generic = method.MakeGenericMethod(type);
    var set = generic.Invoke(db, null);
}

Of course set will be an object here, and you'll have to cast it somehow, which is still part of the problem.

When it boils down to it, if you aren't going to work with statically compiled types, you're going to have to keep dealing with reflection, particularly when you have generic types to deal with (ie DbSet<T>, among others). You have to get them cast to a static type at some point to call the methods, or keep doing MethodInfo.Invoke's.

Another option is to use dynamic, but you can't use dynamics with c# extension methods (without casting to a concrete type) so you're back in the same boat of no Linq support.

Using Linq by reflection is a huge pain.

To be honest, If you have 100 classes, I'd just bite the bullet and write the hard coded types, or use a code generator to do it for you like CodeSmith.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.