2011-10-05 64 views
0

我试图通过将大量模型实体包装到单个视图模型实体中来创建SelectList在选择列表中使用视图模型时出现Linq to Entities错误

我有一个视图模型类:

public class ReferenceDocumentSelectionViewModel 
{ 
    public ReferenceDocument Document { get; set; } 

    public int ID { get { return Document.ID; } } 

    public String DisplayText 
    { 
     get 
     { 
      return Document.DocumentNumber + 
        Document.Version + 
        Document.Revision + 
        Document.Sheet; 
     } 
    } 
} 

然后我试图使用拉姆达expressesions创建这些对象的列表:它们分配到SelectList

var docs = _db.ReferenceDocuments 
       .Select(r => new ReferenceDocumentSelectionViewModel() 
       { 
        Document = r 
       }); 

ReferenceDocList = new SelectList(docs.OrderBy(r => r.DisplayText), 
            "ID", 
            "DisplayText"); 

在我看来,我像这样访问SelectList:

@Html.DropDownListFor(model => model.SelectedReferenceDoc, 
         Model.ReferenceDocList, 
         "-Select-", 
         new { id = "ReferenceList" }) 

其中model.SelectedReferenceDoc是另一视图模型上的整数属性。

我想这会工作,而是我发现了以下错误:

The specified type member 'DisplayText' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

帮助?

编辑:在进一步调查,它似乎是导致此问题的docs.OrderBy(r => r.DisplayText)。如果我删除它,它工作正常。任何想法为什么这是不被允许的?

回答

3

由于DisplayText不是映射属性,EF不知道如何将其转换为SQL。这就是为什么它给你一个错误。

您可以使用LINQ到对象先装入这里排序的所有元素

var docs = _db.ReferenceDocuments 
       .Select(r => new ReferenceDocumentSelectionViewModel() 
       { 
        Document = r 
       }).ToList(); 

然后在内存

ReferenceDocList = new SelectList(docs.OrderBy(r => r.DisplayText), 
            "ID", 
            "DisplayText"); 

排序或按每个属性进行排序

var docs = _db.ReferenceDocuments 
       .OrderBy(r => r.DocumentNumber) 
       .ThenBy(r => r.Version) 
       .ThenBy(r => r.Revision) 
       .ThenBy(r => r.Sheet) 
       .Select(r => new ReferenceDocumentSelectionViewModel() 
       { 
        Document = r 
       }); 

ReferenceDocList = new SelectList(docs, 
            "ID", 
            "DisplayText"); 

这种方式排序将在数据库中完成,比在内存中进行排序要有效得多。

因此,第二个选项是首选。

+0

另一种选择是.AsEnumerable() – MerickOWA

+0

非常好,谢谢你的解决方案!你能解释为什么这是做到这一点的方法吗?哪一个会更有效率,第一个选项还是第二个选项? – link664

+3

其必要的原因是因为传递给DropDownListFor的数据仍然是IQueryable。在该上下文中完成的任何排序都会尝试转换为SQL。因此,通过'DisplayText'进行排序将不起作用,因为该值仅通过C#代码派生。仅通过数据库列进行排序是一种解决方法,或者通过“AsEnumerable”转换为简单的“IEnumerable”是另一种方法(后者允许CLR对数据进行排序而不是数据库)。 – Jacob