2

My Entityframework context :

public class MyContext : DbContext
{
    public DbSet<Company> Companies { get; set; }
    public DbSet<Contact> Contacts { get; set; }
    public DbSet<Event> Events { get; set; }        
}

My method to add objects:

public void AddObject(DbContext context, Type t, object object_to_add)
{      
     PropertyInfo context_property = 
            context.GetType().GetProperties()
           .Where(p => typeof(IEnumerable).IsAssignableFrom(p.PropertyType)
                       && p.PropertyType.GenericTypeArguments.Any()
                       && p.PropertyType.GenericTypeArguments.First() == t)
           .Single();

     DbSet db_set = (DbSet)context_property.GetMethod.Invoke(context, null);

     db_set.Add(object_to_add);
}

But the code crashes when I try to cast a DbSet<> to DbSet,

I'm using reflection because I receive DTO objects that I map to an existing model(via reflection as well), I don't want to code an add method for each new model (I have like 40 and the list is exponentially growing)

Blockquote

Any solution?

AGB
  • 2,230
  • 1
  • 14
  • 21
Akli
  • 1,351
  • 1
  • 15
  • 28

2 Answers2

7

I think is easier if you create a generic method:

public void AddObject<T>(DbContext context,  T object_to_add)
{
   context.Set<T>().Add(object_to_add);
}

Yo can use Set<TEntity> method as I show above.

ocuenca
  • 38,548
  • 11
  • 89
  • 102
  • That will force me to use this ugly code : GetMethod("AddObject").MakeGenericMethod(t).Invoke(this, new object[] { context, object_to_add}); – Akli Apr 12 '16 at 20:16
  • Anyway I'll accept your answer if there isn't another solution – Akli Apr 12 '16 at 20:16
  • 1
    To avoid invoke that method by reflection i would use dependency injection instead. You can use, eg, some patterns like Repository and UnitOfWork, all represented with interfaces, Later using DI you can provide an implementation of those interfaces and invoke the proper method pretty similar as I show above, avoiding the ugly code using reflection. This [codeplex project](https://genericunitofworkandrepositories.codeplex.com/) could be a good start – ocuenca Apr 12 '16 at 20:29
3

Using reflection in a production environment will yield a poor performance. So octaviocci's method is better in every way.

However if you cannot make your method generic, you can try

public void AddObject(DbContext context, Type t, object object_to_add)
{
   context.Set(t).Add(object_to_add);
}

You are getting InvalidCastException because System.Data.Entity.DbSet<TEntity> does not implement System.Data.Entity.DbSet.

See the definition on https://msdn.microsoft.com/en-us/library/gg696460(v=vs.113).aspx

public class DbSet<TEntity> : DbQuery<TEntity>, IDbSet<TEntity>, 
    IQueryable<TEntity>, IEnumerable<TEntity>, IQueryable, IEnumerable
  • Any serializer/parser uses reflection, don't you use one? and yes I use reflection in production, works like a charm takes 1second for 140 classes (1000 objects), 90% of the code elimintaed, just index you objects. – Akli Apr 12 '16 at 20:21
  • 1
    @Akli I also included another a not-generic solution. –  Apr 12 '16 at 20:27
  • See this post about performance impact of reflection: http://stackoverflow.com/questions/25458/how-costly-is-net-reflection. IMHO it is best to avoid it as long as possible. –  Apr 12 '16 at 20:28
  • BTW you are right, most of the serializers use reflection. But they at least try to cache the reflection information. –  Apr 12 '16 at 20:31
  • Thanks exactly what I wanted ;) and +1 for everyone – Akli Apr 12 '16 at 20:34