【问题标题】:Expression Tree error: Unable to create a constant value of type表达式树错误:无法创建类型的常量值
【发布时间】:2011-12-16 21:55:34
【问题描述】:

这是错误:无法创建类型为“mvcinfosite.ViewModels.GrpSearchHolder”的常量值。此上下文仅支持原始类型(“例如 Int32、String 和 Guid”)。

我该如何解决这个错误。 我做一个小例子来告诉你我的问题。在我的真实项目中,MyGrp1,MyGrp2,MyGrp3 被 ListBox 替换。我用它来过滤我的数据。

        public class MyGroupHolder
        {
            public string GrpName { get; set; }
            public List<int ?> ListSelectedGrpDescID { get; set; }
        }


        public ActionResult Index()
        {
            //Database Context
            DBEntities db = EntityFactory.GetEntity();

            //Variables
            List<MyGroupHolder> ListGrpHolder = new List<MyGroupHolder>();

            //Imagine a 3 listbox (MyGrp1,MyGrp2,MyGrp3) 
            //Each listbox contains selected value.
            MyGroupHolder MyGrp1 = new MyGroupHolder();
            MyGrp1.GrpName = "Grp 1 Test";
            MyGrp1.ListSelectedGrpDescID = new List<int?>();
            MyGrp1.ListSelectedGrpDescID.Add(55);


            MyGroupHolder MyGrp2 = new MyGroupHolder();
            MyGrp2.GrpName = "Grp 2 Test";
            MyGrp2.ListSelectedGrpDescID = new List<int?>();
            MyGrp2.ListSelectedGrpDescID.Add(56);


            MyGroupHolder MyGrp3 = new MyGroupHolder();
            MyGrp3.GrpName = "Grp 3 Test";
            MyGrp3.ListSelectedGrpDescID = new List<int?>();
            MyGrp3.ListSelectedGrpDescID.Add(57);

            ListGrpHolder.Add(MyGrp1);
            ListGrpHolder.Add(MyGrp2);
            ListGrpHolder.Add(MyGrp3);

            //Getting a list of Locations base on the Group Filter
            var ListLocation = db.Locations.Where(p => ListGrpHolder.Any(pg => pg.ListSelectedGrpDescID.Count == 0 || p.GroupLocations.Select(sg => sg.GrpDescID).Intersect(pg.ListSelectedGrpDescID).Any())).ToList();


            return View();
        }

【问题讨论】:

    标签: asp.net-mvc-2 entity-framework-4 linq-to-entities


    【解决方案1】:

    您不能将应用程序中的对象传递给 linq-to-entities 查询。您必须提取值并将它们作为条件传递。刚开始您的查询就显示了问题:

    .Where(p => ListGrpHolder.Any(...
    

    负责执行 Linq-to-entity 查询的 SQL 服务器应该如何知道 ListGrpHolder 是什么(它存在于您的应用程序的内存中)以及它包含什么值?

    我不完全理解您的查询以及它应该做什么,但您必须严格区分 linq-to-entities 和 linq-to-objects。第一个在 SQL Server 上执行,它只允许传递简单类型进行查询。第二个在您的应用程序中执行,您可以为它们使用任何对象和 linq 构造,但如果您想将它与来自 SQL 服务器的数据一起使用,您必须首先将它们全部加载到您的应用程序并在应用程序的内存中进行过滤服务器。

    【讨论】:

    • 有没有办法使用自定义表达式树将我的查询转换为有效的表达式?
    【解决方案2】:

    将您的查询转换为使用

    来自 db.Locations 中的 l 其中 mycalculatedlocalids.Contains(l.id) 选择 l;

    IQueryable 包含提供者信息,而 IEnumerable (ListGrpHolder) 不包含。 这就是您无法在 sql server 上运行查询的原因。

    【讨论】:

      【解决方案3】:

      我将查询转换为使用 LINQ 而不是 Lambda 方法。当查询以 LINQ 语法编写时,我更容易阅读查询。

      db.Locationpg.ListSelectedGrpDescID.Count == 0 有什么关系?如果 db.Location 为 0,应该返回什么?我暂时保留了这部分查询。

      在尝试寻找解决方案时,最好将问题分解为多个步骤。这是解决问题的第一步。

      首先,我们可以将 ListGrpHolder ID 重构为另一个语句。这将仅返回 int 值并使 ListLocation 查询更易于阅读。

      var SelectedIds = ListGrpHolder.Select(pg => pg.ListSelectedGrpDescID).SelectMany(i => i);
      var ListLocation = (from loc in db.Locations
                          from grp in loc.GroupLocations
                          where SelectedIds.Contains(grp.GrpDescID)
                          select loc).ToList();
      

      如果我们无法简化或更改查询以获得您需要的结果,那么我们可以考虑使用表达式树。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多