Initializing strongly typed objects in LINQ to Entities
Asked Answered
S

5

11

I have a plain old CLR object which is essentially a wrapper for two entity framework objects, I'm doing this so I can pass this wrapper object to a strongly typed view in the MVC framework. My foo wrapper class is very simple:

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

What I have so far for my ListFoosWithBars function is as follows:

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

This doesn't work because evidently LINQ to Entities doesn't support parametrized initialization, an exception is thrown that says just that: "Only parameterless constructors and initializers are supported in LINQ to Entities." I was wondering if there is another way to achieve this same result?

Shoveler answered 17/9, 2009 at 17:42 Comment(0)
C
20

IF you add a parameterless constructor to your FooWrapper and then use object initialization instead, like so:

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;
}
Canton answered 17/9, 2009 at 17:46 Comment(1)
Had the same thing typed, you win.Bourgeon
S
12

Ok, but what if you want FooObject and BarObject to be readonly? It seems a bit backwards to me that they negate the ability to use a constructor on the object.

I can see a lot of people breaking good encapsulation practices in order to utilize object initialization in this scenario.

Skepticism answered 6/12, 2010 at 5:43 Comment(0)
G
6

Why aren't you using the .AsEnumerable()? In that way, you won't need to create a parameterless constructor and that is what you want.

Your code was almost good. Change it to this:

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

I had the same problem today. I had a class with one parameter constructor. This constructor filled a private readonly field which was returned by a property only with a get and not with a set.

Gendron answered 21/6, 2011 at 8:40 Comment(3)
This is by far the best solution to this issue!Clerihew
I would just be very careful with this approach though, you are basically negating the benefits of the Entity framework by calling AsEnumerable. Once you specify that you are effectively bringing all the records from the FooSet Table and then performing the join locally in memory. Just think about the performance implications when you have thousands (or millions) of records.Badinage
@Santo Agreed, this approach causes grinds my machine to a halt with a LINQ statement over 16 tables, takes about five minutes to return a result. Had it almost instantaneous with a comparable SQL statement.Recollect
B
3

Try a different initialization:

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;
}
Biltong answered 17/9, 2009 at 17:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.