Подтвердить что ты не робот

Entity framework - получить объект по имени

У меня есть следующий код (пример):

public dynamic GetData(string name) 
{
    using(var ctx = GetObjectContext()) 
    {
        switch (name) 
        {
        case "entity1":
            return ctx.entity1.ToList();
        case "entity2":
            return ctx.entity2.ToList();
        ......
        default:
            return null;
        }
    }
}

Я хочу избежать переключения в этом примере. Как найти необходимый класс сущности по имени, вызвать метод ToList() и вернуть данные? Могу ли я сделать это с помощью рефлексии? Можете ли вы мне помочь?

4b9b3361

Ответ 1

Вы можете сделать это с помощью отражения, однако вам также понадобится использовать generics, потому что тип списка, возвращаемый методом ToList(), различен для каждого типа сущности.

Вы можете получить доступ к получателю свойств через отражение так:

var enumerable = typeof([ClassNameOfContext]).GetProperty(name).GetValue(ctx, null);

В то время как [ClassNameOfContext] - это имя класса, в котором ctx является экземпляром. Это не очевидно из вашего кода, но вы это знаете: -)

Проблема заключается в том, что enumerable будет object и должен быть добавлен к IEnumerable<EntityType>, где EntityType - тип объекта, к которому вы обращаетесь. Другими словами, это зависит от имени, которое вы передаете. Если вы используете дженерики для определения типа, вы сможете правильно отбросить объект и не обязательно возвращать dynamic.

public TEntity Get<TEntity>(string name)
{
    ...

и преобразуйте линию сверху:

var enumerable = (IEnumerable<TEntity>)(typeof([ClassNameOfContext]).GetProperty(name).GetValue(ctx, null));
return enumerable.ToList();

здесь вы идете!

Приложение: возможно, вы также можете избавиться от строкового параметра - по возможности следует избегать имен типов или свойств в строках, поскольку это не безопасно для типов. Компилятор не распознает его, и функции IDE, такие как рефакторинг, не учитывают его. Проблема здесь в том, что имена свойств обычно представляют собой плюрализованную форму имен типов сущностей. Но вы можете использовать отражение, чтобы найти свойство, тип которого соответствует TEntity. Я оставляю это как упражнение: -)

Ответ 2

Вы можете использовать такой код

private IEnumerable<TEntity> GetList<TEntity>(string connectionString, Func<object, T> caster)
{
    using (var ctx = new DbContext(connectionString))
    {
        var setMethod = ctx.GetType().GetMethod("Set").MakeGenericMethod(typeof(T));

        var querable = ((DbSet<object>)setMethod
        .Invoke(this, null))
        .AsNoTracking()
        .AsQueryable();

        return querable
            .Select(x => caster(x))
            .ToList();
    }
}

Чтобы вызвать следующее:

var branchList = GetList<Branch>("connectionStringName", x => (Branch)x);

Вы можете удалить .AsNoTracking() и удалить .ToList(), тогда вы получите чистый IQueryable, который вы можете запросить дальше.