Reflection + Linq + DbSet

2019-03-30 12:50发布

I use EF code-first 4.1. in my application. Now I want to get entities through WCF services using generic types. I'm trying to reflect generic type and invoke the method ToList of DbSet Object. Here is my code:

 public string GetAllEntries(string objectType)
        {
            try
            {
             var   mdc =
                   Globals.DbConnection.Create(@"some_db_connection", true);

               // Getting assembly for types
                var asob = Assembly.GetAssembly(typeof(CrmObject));
               // getting requested object type from assembly
                var genericType = asob.GetType(objectType, true, true);

                if (genericType.BaseType == typeof(CrmObject))
                {
                    // Getting Set<T> method
                    var method = mdc.GetType().GetMember("Set").Cast<MethodInfo>().Where(x => x.IsGenericMethodDefinition).FirstOrDefault();

                   // Making Set<SomeRealCrmObject>() method
                    var genericMethod = method.MakeGenericMethod(genericType);
                   // invoking Setmethod into invokeSet 
                    var invokeSet = genericMethod.Invoke(mdc, null);
                   // invoking ToList method from Set<> invokeSet 
                    var invokeToList = invokeSet.GetType().GetMember("ToList").Cast<MethodInfo>().FirstOrDefault();

                    //this return not referenced object as result
                    return invokeToList.ToString();
                }

                return null;
            }
            catch (Exception ex)
            {
                return ex.Message + Environment.NewLine + ex.StackTrace;
            }
        }

In fact then I write the code like return mdc.Set<SomeRealCrmObject>().ToList() - works fine for me! But then I use the generic types I cannot find the method ToList in object DbSet<SomeRealCrmObject>().

3条回答
Ridiculous、
2楼-- · 2019-03-30 13:44

ToLIst() is not a member of DbSet/ObjectSet but is an extension method.

You can try this instead

var method = typeof(Enumerable).GetMethod("ToList");
var generic = method.MakeGenericMethod(genericType);
generic.Invoke(invokeSet, null);
查看更多
走好不送
3楼-- · 2019-03-30 13:49

I had a similar situation where I needed a way to dynamically load values for dropdown lists used for search criteria on a page allowing users to run adhoc queries against a given table. I wanted to do this dynamically so there would be no code change on the front or backend when new fields were added. So using a dynamic type and some basic reflection, it solved my problem.

What I needed to do was invoke a DbSet property on a DbContext based on the generic type for the DbSet. So for instance the type might be called County and the DbSet property is called Counties. The load method below would load objects of type T (the County) and return an array of T objects (list of County objects) by invoking the DbSet property called Counties. EntityList is just a decorator object that takes a list of lookup items and adds additional properties needed for the grid on the front-end.

    public T[] Load<T>() where T : class
    {
        var dbProperty = typeof(Data.BmpDB).GetProperties().FirstOrDefault(
            x => x.GetMethod.ReturnType.GenericTypeArguments[0].FullName == typeof(T).FullName);

        if (dbProperty == null)
            return null;

        dynamic data = dbProperty.GetMethod.Invoke(BmpDb, null);
        var list = Enumerable.ToList(data) as List<T>;
        var entityList = new Data.EntityList<T>(list);

        return entityList.Results;
    }
查看更多
Fickle 薄情
4楼-- · 2019-03-30 13:50

Eranga is correct, but this is an easier usage:

dynamic invokeSet = genericMethod.Invoke(mdc, null);
var list = Enumerable.ToList(invokeSet);

C# 4's dynamic takes care of the cumbersome generic reflection for you.

查看更多
登录 后发表回答