【问题标题】:Linq to Entities error when using a view model in a select list在选择列表中使用视图模型时,Linq to Entities 错误
【发布时间】:2011-10-05 01:00:56
【问题描述】:

我正在尝试通过将一大堆模型实体包装在单个视图模型实体中来创建 SelectList

我有一个视图模型类:

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

然后我尝试使用 lambda 表达式来创建这些对象的列表:

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

在将它们分配给SelectList之前:

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

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

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

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

我认为这可行,但我收到以下错误:

LINQ to 中不支持指定的类型成员“DisplayText” 实体。只有初始化器、实体成员和实体导航 支持属性。

帮助?

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

【问题讨论】:

    标签: c# .net linq linq-to-entities


    【解决方案1】:

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

    您可以在此处使用 LINQ-to-Objects 排序,首先加载所有元素

    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");
    

    这种方式在数据库中进行排序,比在内存中进行排序效率更高。

    因此首选第二个选项。

    【讨论】:

    • 另一种选择是 .AsEnumerable()
    • 太好了,感谢您的解决方案!你能解释一下为什么这是这样做的吗?第一个选项和第二个选项哪个更有效?
    • 之所以需要,是因为传入DropDownListFor的数据仍然是IQueryable。在该上下文中完成的任何排序都将尝试转换为 SQL。因此,按DisplayText 排序将不起作用,因为该值仅通过 C# 代码派生。仅按数据库列排序是一种解决方法,或者通过AsEnumerable 转换为普通的IEnumerable 是另一种方法(后者让CLR 对数据而不是数据库进行排序)。
    • 神奇的埃兰加,正是我正在寻找的答案。感谢您的评论@Jacob。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-20
    • 2018-02-20
    • 1970-01-01
    • 2015-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多