доступ и запрос DbSet из DbContext по имени

как получить доступ и запросить DbSet DbContext по имени (передав строку с именем объекта или полным именем)

что-то вроде (но это не работает)

string myTypeName= "mycustomtype";   //or  "mynamespace1.mynamespace2.mycustomtype"  
Type myType = Type.GetType(myTypeName);
var dbset = db.Set(myType);

// i can't query dbset
//i should do something like this (but i don't know how to do it)
var result = ((IEnumerable<myType>)db.Set(myType)).toList();

person alex    schedule 28.09.2016    source источник


Ответы (1)


@Алекс,

Я потратил на это много времени. Я не смог найти такой простой способ, как ваш метакод в вопросе. Я буду рад улучшениям ниже.

Моя потребность может отличаться от вашей, поэтому позвольте мне объяснить:

  1. Легко создать экземпляр класса по строке. Здесь на SO много примеров.
  2. Что НЕ просто (я почти уверен), так это то, как создать экземпляр класса, который вы можете просто добавить в свой контекст:

ctx.SomeModels.Add(myClass);

... который будет работать с:

ctx.SaveChanges();
  1. Я обнаружил, что класс в игре должен исходить из DbContext, чтобы он мог принять его обратно или даже использовать в Delete()...

Если это соответствует вашему сценарию, это может помочь.

Примечания:
- Я удалил все свои журналы (с помощью NLog), что добавляет много отладки, но затрудняет чтение.
- Если вы сделаете несколько точек останова и посмотрите на значения и варианты , вы увидите некоторые вещи, которые мне пришлось исправить.
- Проблема состоит из 2 частей:
1. Нахождение версии сборки имени класса из простой.
2. Использование этого удобного для компьютера имени для создания класса, который заставит DbContext не жаловаться:

/****************************************************************
 * 
 * CreateInstanceOf
 *     DbTableName = SOMETHINGS <--- note pluralization
 *     BaseAssembly = Assembly for your calling project-NOT this DLL 
 *     (if this is in a dll)...
 * 
 * This method is given a table name (plural), and returns an instance 
 *     of that Model' class (singular)... Failing that, returns null.
 */
public object CreateInstanceOf(string DbTableName, Assembly BaseAssembly)
{
    string className = String.Empty;
    string baseClassName = String.Empty;
    string trimmedClassName = String.Empty;
    string qualifiedAssemblyName = String.Empty;
    try
    {
        /**********************
         * 
         * Part 1 - just get the details on a matching class... 
         *
         */
        foreach (var t in BaseAssembly.GetTypes())
        {
            if (((String)t.Namespace == null) || (!t.Namespace.Contains("Models"))) // adjust to suit (I'm in MVC here)
            {
                // Type is not in Models namespace... skipping
                continue; // just looking for classes in the Models namespace (MVC)
            }
            foreach (var cat in t.CustomAttributes)
            {
                foreach (var car in cat.ConstructorArguments)
                {
                    if (car != null)
                    {
                        t.Name, cat.ToString(), car.ToString());
                        char[] charsToTrim = { '"', ' ' }; // weird how there are actual quotes in the string...
                        string trimmedCar = car.ToString().Trim(charsToTrim); 
                        if (trimmedCar == DbTableName)
                        {
                            // we have a winner!
                            qualifiedAssemblyName = t.AssemblyQualifiedName;
                            baseClassName = trimmedCar;
                            trimmedClassName = (t.Namespace + "." + trimmedCar).Trim(charsToTrim);
                            break;
                        } else
                        {
                            // nothing to see here, move along...
                        }
                    }
                }
            }
        }
        /**********************
         * 
         * Part 2 - create the class with this info... 
         *
         */
        if ((trimmedClassName != null) && (trimmedClassName.Length > 0))
        {
            Type tipe = Type.GetType(qualifiedAssemblyName);
            AssemblyName an = BaseAssembly.GetName();
            char[] charsToTrim = { '"', ' ' };
            string trimmedManModName = BaseAssembly.ManifestModule.Name.ToString().Trim(charsToTrim);
            var result = Activator.CreateInstance(
                tipe
                );
            return result;
        } else
        {
            throw new ArgumentNullException();
        }
    }
    catch (Exception ex)
    {
        return null;
    }
}
person Yumi Koizumi    schedule 19.11.2016
comment
Я дважды прочитал ваш код, но ничего не нашел для ответа на вопрос @alex ... Не могли бы вы сказать, что именно мы должны? - person Ali; 17.06.2017
comment
Этот код создает объект указанного типа, который можно запрашивать. Попытайся. - person Yumi Koizumi; 12.10.2018