实体不能在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查询的闭包中使用带有new的ClassType , only 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 newLinq to EntityClassTypes from new关键字removeClassTypes from newLinq 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}; }