4

Purpose: I need to get the name of the dbset name of the entity typeof(UserAccount) = "UserAccounts". But in runtime I need a common type for the loop and therefor do not know example "UserAccount". Only the "name" from typeof?

I have created an DbContext with some entities. I have been googling for some time but it do not seem to be working for me because of the Type converting?

Please see my method GetDbSetName in the bottom of this description.

I am pretty new at this EF stuff - so please help med with my issue as described below ;-)

public class MyEntities : DbContext
{
    public DbSet<UserAccount> UserAccounts { get; set;}
    public DbSet<UserRole> UserRoles { get; set; }
    public DbSet<UserAccountRole> UserAccountRoles { get; set; }
}

Defined a list of Type to control the output:

public static List<Type> ModelListSorted()
{
    List<Type> modelListSorted = new List<Type>();
    modelListSorted.Add(typeof(UserRole));
    modelListSorted.Add(typeof(UserAccountRole));
    modelListSorted.Add(typeof(UserAccount));
    return modelListSorted;
}

The problem is below using Type - If I use "UserAccount" it Works and I get "UserAccounts". But I do not have the "UserAccount" in runtime as I am in a loop with a serie of types. I do only have the Type list giving the e

public static loopList()
{
    List<Type> modelListSorted = ModelListSorted();
    foreach (Type currentType in modelListSorted)
    {
         string s = DataHelper.GetDbSetName(currentType, db);
    } 
}

HERE IS THE METHOD GIVING ME THE CHALLANGES ;-) Meaning not compiling. saying I am missing a assembly? I know it is pretty pseudo but can this be done smoothly?

public static string GetDbSetName(Type parmType, MyEntities db)
{
    string dbsetname = (db as IObjectContextAdapter).ObjectContext.CreateObjectSet<parmType>().EntitySet.Name;
    return dbsetname;
}
pladekusken
  • 140
  • 2
  • 7

1 Answers1

3

The challenge here is that two reflection steps are involved, one to invoke the generic CreateObjectSet method and one to get the EntitySet from the result. Here's a way to do this:

First, the method:

string GetObjectSetName(ObjectContext oc, MethodInfo createObjectSetMethodInfo,
                        Type objectSetType, Type entityType)
{
    var objectSet = createObjectSetMethodInfo.MakeGenericMethod(entityType)
                                             .Invoke(oc, null);
    var pi = objectSetType.MakeGenericType(entityType).GetProperty("EntitySet");
    var entitySet = pi.GetValue(objectSet) as EntitySet;
    return entitySet.Name;
}

As you see, I first get the ObjectSet by invoking the MethodInfo representing the generic method CreateObjectSet<T>(). Then I find the PropertyInfo for the EntitySet property of the generic type ObectSet<T>. Finally, I get this property's value and the name of the obtained EntitySet.

To do this, I first get a MethodInfo for CreateObjectSet<>() (the one without parameters) and the ObjectSet<> type

var createObjectSetMethodInfo = 
    typeof(ObjectContext).GetMethods()
                         .Single(i => i.Name == "CreateObjectSet" 
                                   && !i.GetParameters().Any());

var objectSetType = Assembly.GetAssembly(typeof(ObjectContext))
                            .GetTypes()
                            .Single(t => t.Name == "ObjectSet`1");

In GetObjectSetName their generic parameters are specified by a concrete entity type, which is done by these "MakeGeneric..." methods.

var oc = (dbContextInstance as IObjectContextAdapter).ObjectContext;
var entityType = typeof(UserRole);
var name = GetObjectSetName(oc, createObjectSetMethodInfo, objectSetType, entityType);

In EF 6 these should be the usings:

using System.Data.Entity.Core.Metadata.Edm
using System.Data.Entity.Core.Objects
using System.Data.Entity.Infrastructure
using System.Linq
using System.Reflection
Gert Arnold
  • 105,341
  • 31
  • 202
  • 291
  • Hi @GertArnold. Thanks for your reply - Nice and simple thinking! I am getting error at the line: `var objectSet = createObjectSetMethodInfo.MakeGenericMethod(entityType).Invoke(oc, null);` Exception message: {"Object does not match target type."} – pladekusken Oct 19 '14 at 16:09
  • I think the issue is around here: `var oc = (dbContextInstance as IObjectContextAdapter).ObjectContext;` As we expect System.Data.Objects.ObjectContext but are getting System.Data.Entity.Core.ObjectContext? - But I can not figure how to resolve it? – pladekusken Oct 19 '14 at 16:09
  • Also this line `var entitySet = pi.GetValue(objectSet) as EntitySet;` Exception message: {"Object does not match target type."} can you also help resolving this along with the previous? – pladekusken Oct 19 '14 at 16:50
  • I had the Framework 6.1.1 in my references? Now I have removed it and installed it again. I can now compile your code with not changes i have following usings: System.Linq; System.Reflection; System.Data.Entity.Core.Objects; System.Data.Metadata.Edm; using System.Data.Entity.Infrastructure; – pladekusken Oct 19 '14 at 18:33
  • But this line `var entitySet = pi.GetValue(objectSet) as EntitySet;` is returning null. when debugging i can see the vaules in objectSet used for the GetValue method? – pladekusken Oct 19 '14 at 18:34
  • That should be in `System.Data.Entity.Core.Metadata.Edm`. I'll add the usings to my answer, because they are very confusing since EF changed them in v6. – Gert Arnold Oct 19 '14 at 18:38
  • YES! It works beautiful. Thank you so much for your experience and patience :-) – pladekusken Oct 19 '14 at 18:41
  • here is better approach http://stackoverflow.com/questions/2686419/get-the-entityset-name-from-an-entitytype-in-ef – SalientBrain May 01 '17 at 10:55