Entity Framework - LINQ - динамические имена столбцов - PullRequest
0 голосов
/ 11 октября 2018

Я знаю, что этот вопрос задавался несколько раз, но чем больше ответов я встречал, тем больше я запутывался.

Учитывая, что у меня есть таблица Categories и в столбцах этой таблицы: Category1, Category2, Category3 и т. Д. Как я могу написать метод, описанный ниже, и использовать параметр (в данном случае catno)

Как можно проще;

public List<string> GetProductCategories(int catno)
{
    using (var ctx = new myEntities())
    {
        return (from c in ctx.Categories
                select c.Category1).ToList();
               //1 being the catno parameter obviously
    }
}

Я определенно НЕ хочу использовать библиотеку Dynamic Linq, так как она не является безопасной для типов.И хотя (и, очевидно) рабочий ответ подойдет, подробное объяснение проблемы и ее решение предоставлены.

Заранее спасибо

Ответы [ 3 ]

0 голосов
/ 11 октября 2018

Если вам нужна полная безопасность типов, я не вижу другого способа, кроме как использовать регистр переключателя для сопоставления целого числа с соответствующей категорией:

public List<string> GetProductCategories(int catno)
{
    using (var ctx = new myEntities())
    {
        switch (catno)
        {
            case 1:
                return ctx.Categories.Select(c => c.Category1).ToList();
            case 2:
                return ctx.Categories.Select(c => c.Category2).ToList();
            default:
                throw new ArgumentException("Category number not supported!");
        }
    }
}

Другая вещь, которую вы, очевидно, можете сделать, - это рефакторингваш код, так что у вас есть список классов Category, который содержит ваше строковое свойство, а также число, тогда вы можете написать что-то вроде этого:

return ctx.Categories.Where(c => c.CategoryNumber == catno)
    .Select(c => c.CategoryDescription)
    .ToList();

Я думаю, что вы, вероятно, должны реорганизовать свой код.Я чувствую плохой дизайн, когда вижу "Category1" и "Category2", звучит так, как будто это должны быть элементы в списке категорий.

Также комментарий о Dynamic Linq, нет ничего плохого в использовании динамического linq, если дляНапример, вы получаете запрос от клиента, который находится вне вашего контроля.Вы можете просто вернуть ошибку, если свойство не найдено.

0 голосов
/ 11 октября 2018

Вы можете определить выражение, которое выбирает свойство на основе имени строки.Затем в интерфейсе IQueryable вы можете использовать его в аргументе Select.Для этого вам потребуется использовать синтаксис метода:

public List<string> GetProductCategories(int catno)
{
    var parameter = Expression.Parameter(typeof(Category));
    var property = Expression.Property(parameter, $"Category{catno}");
    var selector = Expression.Lambda<Func<Category, string>>(property, parameter);

    using (var ctx = new myEntities())
    {
        return ctx.Categories
            .Select(selector)
            .ToList();
    }
}

Expression.Property метод выполняет некоторые проверки типов, поэтому, если для типа Category не определено заданное свойство, оно вызовет исключение.Например, это не удастся, если нет свойства Category0:

var property = Expression.Property(parameter, "Category0");
0 голосов
/ 11 октября 2018
public List<string> GetProductCategories(int catno)
{
    string catName = string.Format("Category{0}", catno);
    using (var ctx = new myEntities())
    {
        var result = ctx.Categories.Select(x => {
                var prop = x.GetType().GetProperty(catName);
                if (prop == null)
                {
                    return double.NaN;
                }
                return double.Parse(prop.GetValue(x).ToString());
            }).ToList();
        return result.Where(x => !double.IsNaN(x)).ToList();
    }
}
...