Вызов пользовательского (форматирующего) метода в LINQ to Entities - PullRequest
2 голосов
/ 30 августа 2011

Я использую EF 4.1 и пытаюсь перечислить список компаний для сетки. У меня есть два варианта в текущем проекте: выбрать все компании из DbContext (Entities) и загрузить их в объект неанонимного типа (скажем, EmpresaGrid) или выделить все компании в объекты анонимного типа с одинаковыми структура типа Empresa (из которой я выбираю сущность).

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

Итак, первый вопрос : лучше создать класс модели только для отображения данных или использовать анонимный тип? О прямом выборе не может быть и речи: SELECT * слишком велик, и это может сделать все чертовски медленным (я полагаю). Поэтому выбор в другой тип создает пользовательский запрос только с необходимыми полями.

Используя второй вариант (анонимный тип), у меня есть этот код (упрощенная версия):

public static IEnumerable<object> Grid()
{
    Entities db = new Entities();

    var empresas = db.Empresas
        .Select(e => new
        {
            Cgc = e.Cgc, // PK
            (...)
            Address = new
            {
                AddressLine = e.EnderecoSede.AddressLine,
                (...)
            }
        },
        Contato = e.Contato,
        (...)
    })
    .ToList();

    return empresas;
}

Анонимный тип, который я создаю, содержит около 40 строк кода, поэтому он довольно большой, но он воссоздает часть структуры класса Empresa (поскольку сетка ожидает объект Empresa). Во всяком случае, у меня проблема с форматом данных. Например, я хотел бы отформатировать свойство Cgc, используя пользовательский формат строки. У меня есть публичный метод для этого, FormataCgc. Этот метод получает строку и возвращает ее в формате, используя некоторые внутренние условия.

Итак, моя проблема в том, как это сделать. Например, я пробовал это:

var empresas = db.Empresas
    .Select(e => new
    {
        Cgc = FormataCgc(e.Cgc),
    }

Но это не работает, потому что FormataCgc не может быть переведен в SQL (и я не хочу его преобразовывать). Я также попробовал это:

var empresas = db.Empresas
    .Select(e => new
    {
        (...)
    }
    .ToList();

foreach (var e in empresas) {
    e.Cgc = FormataCgc(e.Cgc);
}

Но это невозможно сделать, поскольку анонимные типы имеют только свойства только для чтения.

Итак, мой второй вопрос : как именно я могу это сделать? Мне нужно изменить данные после выбора, но с использованием анонимных типов? Я провел небольшое исследование, и лучшее, что я нашел, было следующее: Вызов пользовательского метода в запросе LINQ . В этом решении Ладислав предложил сделать второй выбор из IEnumerable, но, поскольку сетка исключает Empresa, я не могу этого сделать (мне нужно изменить или добавить свойства, а не инкапсулировать их).

Я не уверен, был ли я достаточно ясен, но не стесняйтесь задавать любые вопросы. Кроме того, сеткой, которую я сейчас использую, является Telerik ASP.NET MVC Grid, которая получает IEnumerable (где T - класс) в качестве данных модели и выполняет итерацию каждого объекта, выполняя свою магию.

Ответы [ 2 ]

4 голосов
/ 30 августа 2011

Поскольку вы уже конвертируете это в IEnumerable<T>, вы можете выполнять пользовательское форматирование при потоковой передаче результатов на клиенте. Сделайте свой db.Select, а затем конвертируйте в соответствующий формат, то есть:

var empresas = db.Empresas
    .Select(e => new
    {
        (...)
    })
    .ToList();

foreach (var e in empresas) {
    yield return new {
       Cgc = FormataCgc(e.Cgc),
       // Copy other properties here, as needed...
    };
}

При этом я лично рекомендую создать пользовательский класс, а не возвращать анонимный тип. Ваше преобразование будет:

foreach (var e in empresas) {
    yield return new YourClass(FormataCgc(e.Cgc), ...); // Construct as needed
}

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

1 голос
/ 30 августа 2011

Я думаю, что решение обоих ваших вопросов - создать класс модели. Конечно, это немного больше работы заранее, но это даст вам большую гибкость в долгосрочной перспективе. Ваш класс модели может затем обработать форматирование для вас.

public class EmpresaGridModel
{
    public string Cgc { get; set; }

    public string CgcFormatted 
    {
        return FormataCgc(this.Cgc);
    }

    //properties for the other fields will have to be created as well obviously
}

Ваша сетка telerik может быть привязана непосредственно к свойству CgcFormatted

...