在LINQ to Entities中初始化强类型对象

11

我有一个普通的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中会抛出一个异常,提示:"只支持无参构造函数和初始化程序"。我想知道是否有其他方法可以实现同样的结果?

5个回答

20

如果你为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;
}

3
你打出了同样的内容,你赢了。 - AdamSane

12

好的,但如果你想让FooObject和BarObject是只读的呢?对我来说,它似乎有点不合逻辑,因为它们消除了在对象上使用构造函数的能力。

我可以看到很多人为了在这种情况下利用对象初始化而破坏了良好的封装实践。


6
为什么不使用.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;
}

我今天遇到了同样的问题。我有一个只有一个参数的构造函数的类。这个构造函数填充了一个私有的只读字段,该字段仅通过get而不是set返回。


这绝对是解决这个问题的最佳方案! - Silas Hansen
8
不过,我建议你小心使用这种方法,因为你调用AsEnumerable方法实际上会削弱Entity Framework的优势。一旦指定了该方法,就相当于将FooSet表中的所有记录都带入内存中进行连接操作。当你有成千上万甚至数百万条记录时,请考虑性能方面的影响。 - Alan
@Santo同意,这种方法会导致我的机器在对16个表进行LINQ语句时停滞不前,需要大约五分钟才能返回结果。而使用类似的SQL语句几乎可以瞬间完成。 - wonea

3

尝试使用不同的初始化方法:

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接