此上下文仅支持原始类型或枚举类型

Posted

技术标签:

【中文标题】此上下文仅支持原始类型或枚举类型【英文标题】:Only primitive types or enumeration types are supported in this context 【发布时间】:2013-03-04 21:21:22 【问题描述】:

我已经看到了很多关于这个主题的问题,但我无法对任何一个真正解决我所看到的问题的问题进行分类。我有一个活动实体,它跟踪分配给哪个员工以及哪个员工创建并更新了记录。如果我删除 `where a.AssignedEmployee == currentUser' 代码行,我不会得到下面的运行时错误。

无法创建“DataModels.Employee”类型的常量值。仅有的 在此上下文中支持原始类型或枚举类型。

控制器

var query = from a in db.Activities
            where a.AssignedEmployee == currentUser
            where a.IsComplete == false
            orderby a.DueDate
            select a;
return View(query.ToList());

查看

@model IEnumerable<Data.DataModels.Activity>
..........

【问题讨论】:

== 是否执行此方案不支持的引用相等?注意:询问是否不支持 ref 相等性 @JaredPar 你说得对……今天的白痴奖给了我。我在周日尝试了 18 种不同的方法来编写此查询,但由于某种原因,在该对象上使用 ID 属性并不是其中之一。我会把它归咎于今天没有星巴克。 咖啡是你的朋友 ;) 【参考方案1】:

我的猜测是该错误表明 EF 无法将 Employee 的相等运算符转换为 SQL(无论您是假设引用相等还是覆盖 == 运算符)。假设Employee 类有一个唯一标识符试试:

var query = from a in db.Activities
            where a.AssignedEmployeeId == currentUser.Id
            where a.IsComplete == false
            orderby a.DueDate
            select a;
return View(query.ToList());

【讨论】:

那太糟糕了...如果 NHibernate 中有一个 Id 工作正常...我知道添加 .Id 并没有那么糟糕,但没有 .Id 更优雅...【参考方案2】:

它不喜欢您尝试将整个对象相等性转换为数据库查询的事实。您只能使用常量值执行实体框架查询,就像您执行 SQL 查询一样。解决这个问题的方法是比较 ID 以查看 AssignedEmployee 的 ID 是否与员工表中当前用户的 ID 相同。

附带说明,如果您正在跟踪的 currentUser 对象不是 Employee 类型,您可能需要考虑缓存该用户的相应 Employee 记录,以便在以后的查询中更好地引用它。这比试图不断地通过那张桌子要好得多。 (同样,这只会影响你,如果它实际上是在不同的表中)

【讨论】:

【参考方案3】:

使用 == 和 obj.Equals 的问题在于实体框架不知道如何将该方法调用转换为 SQL ——即使您将这两个方法重载为可以转换为 SQL 的方法。在 Entity Framework 中解决这个缺点的方法是创建一个方法,该方法返回一个表达式树,它会执行您想要执行的更复杂的相等性检查。

例如,假设我们有以下类

public class Person 
    public string Firstname  get; set;  
    public string Lastname   get; set; 

为了返回一个Entity Framework可以理解的自定义相等操作,在Person类中添加如下方法:

public static Expression<Func<Person, bool>> EqualsExpressionTree(  Person rhs )

    return ( lhs ) => string.Equals( lhs.Firstname, rhs.Firstname ) &&
                      string.Equals( lhs.Lastname, rhs.Lastname );

在您的 LINQ 查询中,您可以像这样利用您的自定义相等代码:

Person anotherPerson = new Person  Firstname = "John", Lastname = "Doe" 
personCont.Where( Person.EqualsExpressionTree(anotherPerson) );
//...
if ( personCont.Any( Person.EqualsExpressionTree(anotherPerson)) ) 
//...

此外,可以重写 EqualsExpressionTree 方法以调用静态 Equals 方法,从而允许您利用自定义相等逻辑。但是,无论如何,请记住您的代码必须转换为 SQL 表达式,因为毕竟我们是在调用数据库而不是从内存中访问内容。

【讨论】:

以上是关于此上下文仅支持原始类型或枚举类型的主要内容,如果未能解决你的问题,请参考以下文章

无法创建类型为“x”的常量值。此上下文仅支持原始类型或枚举类型

实体框架,无法创建类型为“XX”的常量值。此上下文仅支持原始类型或枚举类型

无法创建类型为“EShop.ClassLibrary.ProductType”的常量值。此上下文仅支持原始类型或枚举类型

无法创建类型的常量值。此上下文仅支持基元类型或枚举类型。

无法创建“System.Object”类型的常量值。此上下文仅支持基元类型或枚举类型

无法创建“匿名类型”类型的常量值。此上下文仅支持基元类型或枚举类型。