Инициализация сильно типизированных объектов в 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 поддерживаются только конструкторы без параметров и инициализаторы". Мне было интересно, есть ли другой способ добиться этого же результата?

Ответ 1

Если вы добавите конструктор без параметров в свой 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;
}

Ответ 2

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

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

Ответ 3

Почему вы не используете .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;
}

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

Ответ 4

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

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;
}