Jef*_*son 5 c# linq entity-framework
我有一个下面的模型,当我使用下面的 linq 添加 ComboProducts 对象时,出现错误。这段代码中我缺少什么吗?
错误
出现在单个 LINQ to Entities 查询中的两个结构不兼容的初始化中。一个类型可以在同一个查询的两个地方初始化,但前提是在两个地方设置了相同的属性,并且这些属性的设置顺序相同。
模型
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public List<Product> ComboProducts { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
代码
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public List<Product> ComboProducts { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
异常消息很清楚,select new NCCN.Model.Product在一个 LINQ 语句中有两个语句,它们没有以相同的顺序设置相同的属性。这是我们必须处理的 EF 限制。LINQ-to-objects 不会抛出这个异常。
虽然你的问题不是很清楚,但我想我明白你实际上在问什么。即使在理解异常消息时,如何处理它也不是很明显。在指出问题之前,让我先介绍一个简化的模型。
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public ICollection<ProductComponent> Components { get; set; }
}
public class ProductComponent
{
public int ProductId { get; set; }
public int ComponentProductId { get; set; }
public Product Product { get; set; }
public Product ComponentProduct { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
带映射代码。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ProductComponent>().HasKey(e => new { e.ProductId, e.ComponentProductId });
modelBuilder.Entity<ProductComponent>().HasRequired(e => e.Product)
.WithMany(p => p.Components).HasForeignKey(e => e.ProductId);
modelBuilder.Entity<ProductComponent>().HasRequired(e => e.ComponentProduct)
.WithMany().HasForeignKey(e => e.ComponentProductId)
.WillCascadeOnDelete(false); // Prevent circular cascade
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以使用导航属性而不是一直加入。
任务是将此模型映射到 DTO 类:
public class ProductDto
{
public int ProductId { get; set; }
public string Name { get; set; }
public List<ProductDto> ComboProducts { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
应该很简单
var products = db.Products.Select(p => new ProductDto
{
ProductId = p.ProductId,
Name = p.Name,
ComboProducts =
p.Components.Select(pc => pc.ComponentProduct)
.Select(c => new ProductDto
{
ProductId = c.ProductId,
Name = c.Name,
}).ToList()
});
Run Code Online (Sandbox Code Playgroud)
但是现在EF抛出你报告的异常。在您的情况下,您甚至跳过了整个范围的属性,这里只是ComboProducts在嵌套中ProductDto,但这已经足够了。内部也ProductDto应该有一个ComboProducts集合。
不幸的是,这并不像人们期望的那样简单。例如,使用这个内部选择...
.Select(c => new ProductDto
{
ProductId = c.ProductId,
Name = c.Name,
ComboProducts = null
}).ToList()
Run Code Online (Sandbox Code Playgroud)
...EF 投掷
NotSupportedException:无法创建类型为“System.Collections.Generic.List`1[[ProductDto]]”的空常量值。在此上下文中仅支持实体类型、枚举类型或基本类型。
和...
.Select(c => new ProductDto
{
ProductId = c.ProductId,
Name = c.Name,
ComboProducts = null
}).ToList()
Run Code Online (Sandbox Code Playgroud)
...投掷
NotSupportedException:无法在 LINQ to Entities 查询中初始化实现 IEnumerable 'System.Collections.Generic.List`1[[ProductDto]]' 的类型。
归结为:对于这样的嵌套投影,您必须对主要类型和嵌套类型使用两种不同的类型。但是匿名类型也符合要求,所以我认为解决这个烦人的 EF 限制的最简单方法是投射到匿名类型,然后ProductDto:
.Select(c => new ProductDto
{
ProductId = c.ProductId,
Name = c.Name,
ComboProducts = new List<ProductDto>()
}).ToList()
Run Code Online (Sandbox Code Playgroud)