实体不能在LINQ to Entities查询中构造

有一个实体types叫做产品,是由entity framework生成的。 我已经写了这个查询

public IQueryable<Product> GetProducts(int categoryID) { return from p in db.Products where p.CategoryID== categoryID select new Product { Name = p.Name}; } 

下面的代码会引发以下错误:

“实体或复杂typesShop.Product不能在LINQ to Entities查询中构造”

 var products = productRepository.GetProducts(1).Tolist(); 

但是,当我使用select p而不是select new Product { Name = p.Name}; 它工作正常。

我怎样才能做一个自定义select部分?

您不能(也不应该能够)投影到映射的实体上。 但是,您可以投影到匿名types或DTO上 :

 public class ProductDTO { public string Name { get; set; } // Other field you may need from the Product entity } 

而你的方法将返回一个DTO列表。

 public List<ProductDTO> GetProducts(int categoryID) { return (from p in db.Products where p.CategoryID == categoryID select new ProductDTO { Name = p.Name }).ToList(); } 

您可以投影到匿名types,然后从它到模型types

 public IEnumerable<Product> GetProducts(int categoryID) { return (from p in Context.Set<Product>() where p.CategoryID == categoryID select new { Name = p.Name }).ToList() .Select(x => new Product { Name = x.Name }); } 

编辑 :我会更具体一些,因为这个问题引起了很多关注。

您不能直接投影到模型types(EF限制),所以没有办法解决这个问题。 唯一的方法是投射到匿名types(第一次迭代),然后到模型types(第二次迭代)。

还请注意,当你以这种方式部分加载实体时,它们不能被更新,所以它们应该保持分离状态。

我从来没有完全理解为什么这是不可能的,这个线程的答案没有给出强烈的理由来反对它(主要是关于部分加载的数据)。 这是正确的,在部分加载状态实体不能更新,但是,这个实体将被分离,所以意外的尝试来保存它们是不可能的。

考虑我上面使用的方法:结果我们仍然有一个部分加载的模型实体。 这个实体是分离的。

考虑这个(希望存在的)可能的代码:

 return (from p in Context.Set<Product>() where p.CategoryID == categoryID select new Product { Name = p.Name }).AsNoTracking().ToList(); 

这也可能导致分离的实体列表,所以我们不需要做两次迭代。 一个编译器会很聪明地看到AsNoTracking()已经被使用,这将导致分离的实体,所以它可以让我们做到这一点。 但是,如果省略了AsNoTracking(),它可能会抛出与现在抛出exception相同的exception,以警告我们需要对我们所需的结果足够具体。

还有另一种方法,我find了工作,你必须build立一个从你的产品类派生的类,并使用它。 例如:

 public class PseudoProduct : Product { } public IQueryable<Product> GetProducts(int categoryID) { return from p in db.Products where p.CategoryID== categoryID select new PseudoProduct() { Name = p.Name}; } 

不知道这是“允许”,但它的工作原理。

下面是一个没有声明aditional class的方法:

 public List<Product> GetProducts(int categoryID) { var query = from p in db.Products where p.CategoryID == categoryID select new { Name = p.Name }; var products = query.ToList().Select(r => new Product { Name = r.Name; }).ToList(); return products; } 

但是,只有在想要将多个实体组合到一个实体中时才能使用。 上述function(简单的产品到产品映射)是这样完成的:

 public List<Product> GetProducts(int categoryID) { var query = from p in db.Products where p.CategoryID == categoryID select p; var products = query.ToList(); return products; } 

另一种简单的方法

 public IQueryable<Product> GetProducts(int categoryID) { var productList = db.Products .Where(p => p.CategoryID == categoryID) .Select(item => new Product { Name = item.Name }) .ToList() .AsQueryable(); // actually it's not useful after "ToList()" :D return productList; } 

你可以使用这个,它应该是工作 – >你必须使用toList之前使用select新列表:

 db.Products .where(x=>x.CategoryID == categoryID).ToList() .select(x=>new Product { Name = p.Name}).ToList(); 

只添加AsEnumerable():

 public IQueryable<Product> GetProducts(int categoryID) { return from p in db.Products.AsEnumerable() where p.CategoryID== categoryID select new Product { Name = p.Name}; } 

在回答另一个被标记为重复的问题( 参见这里 )时,我根据Soren的答案找出了一个简单而快速的解决scheme:

 data.Tasks.AddRange( data.Task.AsEnumerable().Select(t => new Task{ creator_id = t.ID, start_date = t.Incident.DateOpened, end_date = t.Incident.DateCLosed, product_code = t.Incident.ProductCode // so on... }) ); data.SaveChanges(); 

注意:此解决scheme仅适用于Task类(此处称为“事件”)上具有导航属性(外键)的情况。 如果你没有这个,你可以用“AsQueryable()”来使用其他解决scheme之一。

如果您使用的是entity framework,那么尝试从DbContext中移除使用您的复杂模型作为实体的属性。当将多个模型映射到名为Entity的视图模型时,我遇到同样的问题

 public DbSet<Entity> Entities { get; set; } 

从DbContext删除条目修复了我的错误。

如果您正在执行Linq to Entity ,则不能在select查询的闭包中使用带有newClassTypeonly anonymous types are allowed (new without type)

看看我的项目的这个片段

 //... var dbQuery = context.Set<Letter>() .Include(letter => letter.LetterStatus) .Select(l => new {Title =l.Title,ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated,LetterStatus = new {ID = l.LetterStatusID.Value,NameInArabic = l.LetterStatus.NameInArabic,NameInEnglish = l.LetterStatus.NameInEnglish} }) ^^ without type__________________________________________________________________________________________________________^^ without type 

你在select闭包中添加了new keyword ,即使在complex properties你会得到这个错误

所以ClassTypes from new Linq to Entity ClassTypes from new关键字remove ClassTypes from new Linq to Entity查询,

因为它会转换成sql语句并在SqlServer上执行

所以什么时候可以使用new with types select封闭new with types

你可以使用它,如果你正在处理LINQ to Object (in memory collection)

 //opecations in tempList , LINQ to Entities; so we can not use class types in select only anonymous types are allowed var tempList = dbQuery.Skip(10).Take(10).ToList();// this is list of <anonymous type> so we have to convert it so list of <letter> //opecations in list , LINQ to Object; so we can use class types in select list = tempList.Select(l => new Letter{ Title = l.Title, ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated, LetterStatus = new LetterStatus{ ID = l.LetterStatus.ID, NameInArabic = l.LetterStatus.NameInArabic, NameInEnglish = l.LetterStatus.NameInEnglish } }).ToList(); ^^^^^^ with type 

在执行ToList查询后,它成为in memory collection所以我们可以在select中使用new ClassTypes

您可以使用数据传输对象(DTO)来解决此问题。

这些有点像viewmodels,你把你需要的属性,你可以映射他们手动在你的控制器或通过使用第三方解决scheme,如AutoMapper。

用DTO的你可以:

  • 使数据可串行化(Json)
  • 摆脱循环引用
  • 通过留下您不需要的属性来减lessnetworkingstream量(viewmodelwise)
  • 使用objectflattening

今年我在学校学习,这是一个非常有用的工具。

您可以将AsEnumerable添加到您的集合中,如下所示:

 public IQueryable<Product> GetProducts(int categoryID) { return from p in db.Products.AsEnumerable() where p.CategoryID== categoryID select new Product { Name = p.Name}; }