1

I have a function which make repository Dictionary, of multiple tables at run time, What i want is make this as generic, but I am stuck on this error..

 public IRepository<TEntity> GetRepository<TEntity>(string TypeName) where TEntity : class 

 {

        Type t = GetInstance(TypeName);
        if (_repositories.Keys.Contains(t))
        {
            return _repositories[t] as IRepository<TEntity>;
        }

        var repository = new Repository<TEntity>(_context);

        _repositories.Add(t, repository);

        return repository;
 }

When I call this function as

 string tn = tt.GetType().FullName;
 Type tttt = GetInstance(tn);
 uu.GetRepository<Object>(tn).Add(tt);

it throws Exception

The entity type Object is not part of the model for the current context.

how can I make this happen as

string tn = tt.GetType().FullName;
Type tttt = GetInstance(tn);
uu.GetRepository<typeof(tt)>(tn).Add(tt);

or something type else.

Faraz Ahmed
  • 1,467
  • 2
  • 18
  • 33

2 Answers2

1

If you want it to be generic, you need to specify a type as a generic parameter. The client code must know the type, not just have an instance of that type.

In your case, using Object as a generic type argument does not make sense, because that would not provide the type inference for the underlying framework. That is the reason for the exception thrown.

Also, at runtime, if your solution is multithreaded, you can't use Dictionary without extra synchronization. For your task, I'd recommend ConcurrentDictionary.

void Main()
{
    var repository = GetRepository<MyEntity1>();
    MyEntity1 instance = repository.Get(1);
}

class MyEntity1
{
}

ConcurrentDictionary<Type, object> repositories = new ConcurrentDictionary<System.Type, object>();

interface IRepository<T>
{
    T Get(int id);
}

class Repository<T> : IRepository<T> where T:new()
{
    public T Get(int id)
    {
        return new T();
    }
}

IRepository<T> GetRepository<T>() where T:new()
{
    return (IRepository<T>)repositories.GetOrAdd(typeof(T), t => new Repository<T>());
}
George Polevoy
  • 7,450
  • 3
  • 36
  • 61
1

If you just want to know how to do it in principle (if ignore questions about should you do that at all or not), then here is how:

 string tn = tt.GetType().FullName;
 // get reference to GetRepository<TEntity>
 var genericGet = uu.GetType().GetMethod("GetRepository").MakeGenericMethod(tt.GetType());
 // invoke to get IRepository<TEntity>
 var repository = genericGet.Invoke(uu, new object[] { tn});
 // get IRepository<TEntity>.Add
 var addMethod = repository.GetType().GetMethod("Add");
 // invoke
 addMethod.Invoke(repository, new object[] { tt});

If you would go this way - better make your Add methods accept object instead of generic type argument, and so make your interface just IRepository, not IRepository<T>. Then inside repository - get reference to specific DbSet and Add method using technique above.

Evk
  • 98,527
  • 8
  • 141
  • 191
  • Yeah, It's Work, but If there any solution other than this? – Faraz Ahmed May 11 '16 at 10:40
  • @user6002727 as I remember, Entity Framework context has untyped DbSets. Something like context.Set(typeof(YourEntity)). You can just use those sets then (again, your IRepository would be without generic parameters). – Evk May 11 '16 at 10:43