Инициализация строго типизированных объектов в LINQ to Entities

У меня есть простой старый объект CLR, который по сути является оболочкой для двух объектов инфраструктуры сущностей, я делаю это, чтобы передать этот объект-оболочку в строго типизированное представление в среде MVC. Мой класс оболочки foo очень прост:

public class FooWrapper
{
    public FooWrapper(Foo f, Bar b)
    {
        this.FooObject = f;
        this.BarObject = b;
    }

    public Foo FooObject { get; private set; }
    public Bar BarObject { get; private set; }
}

То, что у меня есть для моей функции ListFoosWithBars, выглядит следующим образом:

public IEnumerable<FooWrapper> ListFoosWithBars(int userID)
{
    IEnumerable<Bar> tempBar = ListBarsByUserID(userID);
    IEnumerable<FooWrapper> results = (from f in _entities.FooSet
                                       join b in tempBar on f.ID equals b.foos.ID
                                       select new FooWrapper(f, b));
    return results;
}

Это не работает, потому что, очевидно, LINQ to Entities не поддерживает параметризованную инициализацию, выдается исключение, которое говорит именно об этом: «В LINQ to Entities поддерживаются только конструкторы и инициализаторы без параметров». Мне было интересно, есть ли другой способ добиться того же результата?


person Graham Conzett    schedule 17.09.2009    source источник


Ответы (5)


ЕСЛИ вы добавляете конструктор без параметров в свой FooWrapper, а затем вместо этого используете инициализацию объекта, например:

public IEnumerable<FooWrapper> ListFoosWithBars(int userID)
{
    IEnumerable<Bar> tempBar = ListBarsByUserID(userID);

    IEnumerable<FooWrapper> results = (
        from f in _entities.FooSet
        join b in tempBar on f.ID equals b.foos.ID
        select new FooWrapper()
        {
            FooObject = f, 
            BarObject = b
        });

    return results;
}
person Robban    schedule 17.09.2009
comment
Напечатали то же самое, вы выиграли. - person AdamSane; 17.09.2009

Хорошо, но что, если вы хотите, чтобы FooObject и BarObject были доступны только для чтения? Мне кажется немного обратным то, что они отрицают возможность использования конструктора на объекте.

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

person Sam Shiles    schedule 06.12.2010

Почему вы не используете .AsEnumerable()? Таким образом, вам не нужно будет создавать конструктор без параметров, и это то, что вам нужно.

Ваш код был почти хорош. Измените его на это:

public IEnumerable<FooWrapper> ListFoosWithBars(int userID)
{
    IEnumerable<Bar> tempBar = ListBarsByUserID(userID);
    IEnumerable<FooWrapper> results = (from f in _entities.FooSet.AsEnumerable()
                                       join b in tempBar on f.ID equals b.foos.ID
                                       select new FooWrapper(f, b));
    return results;
}

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

person LockTar    schedule 21.06.2011
comment
На сегодняшний день это лучшее решение этой проблемы! - person Silas Hansen; 31.05.2012
comment
Я бы просто был очень осторожен с этим подходом, вы в основном отрицаете преимущества структуры Entity, вызывая AsEnumerable. Как только вы укажете, что вы эффективно переносите все записи из таблицы FooSet, а затем выполняете соединение локально в памяти. Просто подумайте о последствиях для производительности, когда у вас есть тысячи (или миллионы) записей. - person Alan; 09.08.2012
comment
@Santo Согласен, этот подход приводит к остановке моей машины с помощью оператора LINQ для 16 таблиц, для возврата результата требуется около пяти минут. Если бы это было почти мгновенно с сопоставимым оператором SQL. - person wonea; 24.10.2012

Попробуйте другую инициализацию:

public class FooWrapper
{
    public FooWrapper() { }

    public Foo FooObject { get; set; }
    public Bar BarObject { get; set; }
}


public IEnumerable<FooWrapper> ListFoosWithBars(int userID)
{
    IEnumerable<Bar> tempBar = ListBarsByUserID(userID);

    IEnumerable<FooWrapper> results = (
        from f in _entities.FooSet
        join b in tempBar on f.ID equals b.foos.ID
        select new FooWrapper 
        {
            FooObject = f,
            BarObject = b
        });

    return results;
}
person bruno conde    schedule 17.09.2009