James P. Wright
James P. Wright

Reputation: 9131

EntityFramework EntityType from ObjectContext?

I have a method with this signature:

public void GenerateLog<TEntity>(TEntity entity) where TEntity : EntityObject

How can I loop through my ObjectContext and call this for each Entity in my ObjectContext?
I know that I can do this:

foreach (ObjectStateEntry entry in
                context.ObjectStateManager.GetObjectStateEntries(
                EntityState.Added | EntityState.Modified))
{
    string entityName = entry.Entity.GetType().Name;
}

But I don't know how to go from a String representation of the name to GenerateLog<MYSTRING> instead of GenerateLog<TEntity>.

Upvotes: 0

Views: 1075

Answers (2)

Steve Mallory
Steve Mallory

Reputation: 4283

You need to make a generic method from your GenerateLog and then call that. I normally need to mess around a bit before I get something like this to work, but this should be close

MethodInfo generateLog = typeof(YourClass)
    .GetMethod("GenerateLog", BindingFlags.Public | BindingFlags.Instance );

MethodInfo genericGenerateLog = generateLog.MakeGenericMethod(entry.Entity.GetType());

genericGenerateLog.Invoke(this, new object[] { entry.Entity });

YourClass is simply the class the GenerateLog is in.

Upvotes: 2

Steve Wilkes
Steve Wilkes

Reputation: 7135

As Drew Marsh said, there's no way to call a generic method with only the name of the generic Type argument. Because of that, I can only suggest what you may well judge to be a bit of a rubbish solution using runtime method resolution - although it would work...

Firstly, assign a dynamic variable inside the foreach, and call a private method named (e.g.) CallGenerateLog():

foreach (ObjectStateEntry entry in
                context.ObjectStateManager.GetObjectStateEntries(
                EntityState.Added | EntityState.Modified))
{
    dynamic dynamicEntity = entry.Entity;

    CallGenerateLog(dynamicEntity);
}

...provide one overload of CallGenerateLog() for each of the Entity types you want to log, and have each one call your GenerateLog() method, e.g.:

private static void CallGenerateLog(User user)
{
    GenerateLog(user);
}

private static void CallGenerateLog(Customer customer)
{
    GenerateLog(customer);
}

...etc... and provide a catch-all overload which will satisfy the compiler and be called if an Entity type you don't have an explicit overload for is found.

private static void CallGenerateLog(object entity)
{
}

Problems with this include:

  1. You need an overload of CallGenerateLog() for each Entity type, so if you add a new Entity type which you want to log you'll have to remember to add an overload for it (although you could address this with T4 templates)

  2. There is some overhead to runtime method resolution, so you may have to profile how well the method performs and decide if it's going to cause you any problems.

Upvotes: -1

Related Questions