LINQ to Entities不支持指定的类型成员'UsersCount'

Tom*_*mas 1 asp.net-mvc linq-to-entities entity-framework entity-framework-6.1

我有这样的POCO实体

  public class Product : Entity

 {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Id { get; set; }
        [Required]
        [MaxLength(50)]
        public string Name { get; set; }              
        public virtual ICollection<Order> Orders { get; set; }

        [NotMapped]
        public int UsersCount
        {
            get
            {
                return  Orders.Count(); 
            }
        }

}
Run Code Online (Sandbox Code Playgroud)

产品访问方法

 public IQueryable<Product> GetAll()
        {
            return _context.Product.Include(I=>I.Orders);          
        }    
Run Code Online (Sandbox Code Playgroud)

当我将所有产品加载到View中时

      var model = _productService.GetAll().Select(p => new AdminProductViewModel
        {
            Active = p.Active,
            Id = p.Id,
            Name = p.Name,
            UsersCount = p.UsersCount
        }).ToList();
Run Code Online (Sandbox Code Playgroud)

我得到例外

LINQ to Entities不支持指定的类型成员'UsersCount'.

我真的无法理解为什么Linq to Entity会给出异常.也许有人解释了什么是错的?

我们还在另一个应用程序中使用计算字段

 public class User : Entity
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Id { get; set; }               
        [Required]
        [MaxLength(50)]
        public string Email { get; set; }
        [MaxLength(50)]
        public string FirstName { get; set; }
        [MaxLength(50)]
        public string LastName { get; set; }

        public virtual ICollection<Order> Orders { get; set; }
        public virtual ICollection<Statistic> Statistics { get; set; }

        [NotMapped]
        public bool Active
        {
            get
            {
                return Orders.Any(c => c.Active && (c.TransactionType == TransactionType.Order || c.TransactionType == TransactionType.Subscription));
            }
        }

        [NotMapped]
        public int CreditsLeft
        {
            get
            {
                return Orders.Where(w => w.Active).Sum(p => p.Credits != null ? p.Credits.Value : 0);
            }
        }
}

    public User Get(int id)
    {
        return _context.User.FirstOrDefault(u => u.Id == id);
    }

var user = _userService.Get(_authUser.Id);

 var model = new UserViewModel
            {
                Active = user.Active,
                FullName = user.FullName,
                Email = user.Email,
            };
Run Code Online (Sandbox Code Playgroud)

并且没有任何问题,EF6不会给出任何例外,尽管它也有两个计算字段User.ActiveUser.CreditsLeft

Ger*_*old 6

请记住,LINQ to Entities尝试将每个LINQ语句转换为SQL.你的陈述......

var model = _productService.GetAll().Select(p => new AdminProductViewModel...
Run Code Online (Sandbox Code Playgroud)

...是Select针对IQueryable(_productService.GetAll())的LINQ扩展方法().如文档所示,此方法采用Expressionas参数.

您可以将表达式视为表示应执行的任务的标记树.简单地说,LINQ提供程序是一个"表达式语言"中的令牌字典,用于其他语言的标记,在本例中为SQL.整个语句被翻译成SQL并由数据库执行..Net运行时只发送语句并处理返回的结果.

检查EF的源代码表明许多令牌都是硬编码的:所有SQL关键字,一些内置("规范")函数(如DATEDIFF)和一些.Net方法.通过将实体属性映射到数据库列来添加其他标记.最近,ToString()被添加到字典的.Net部分.在EF6中我们可以写...

_context.Product.Select(p => p.Id.ToString())
Run Code Online (Sandbox Code Playgroud)

在此之前,这会引起臭名昭着

LINQ to Entities无法识别方法'System.String ToString()'

您的异常具有相同的原因,但它与成员而不是方法有关.p.UsersCount不在字典中,因为它没有映射.

我们还在另一个应用程序中使用计算字段

这里有一个User从数据库中获取并实现为C#对象.现在,当您访问其属性时,它只是运行.Net代码.这里没有SQL翻译.嗯......它可能触发延迟加载(订单和信用),但访问属性的行为不会发生在表达式的上下文中.

同样,您可以UsersCount在获得Product对象后访问.如果您希望数据库对订单进行大量计算,则必须使用LINQ语句中的表达式:

var model = _productService.GetAll().Select(p => new AdminProductViewModel
    {
        Active = p.Active,
        Id = p.Id,
        Name = p.Name,
        UsersCount = p.Orders.Count()
    }).ToList();
Run Code Online (Sandbox Code Playgroud)