Linq过滤实体的集合最终出现在LINQ to Entities中

时间:2017-05-22 10:43:23

标签: asp.net-mvc entity-framework linq

ASPNET MVC5网络应用

在获取与其他实体的关系由以下模型描述的产品时,我只需要过滤那些language_id等于文化参数的Products.Category.CategoryTrans。

请注意我需要将结果作为IQueryable传递给已经实现的后续分页和排序方法。

型号:

public partial class Product
{
    public int? ID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public bool IsDeleted { get; set; }
    public bool IsApproved { get; set; }
    public int CategoryID { get; set; }
    public virtual Category Category { get; set; }
    [NotMapped]
    public virtual CategoryTrans CategoryTrans { get; set; }
}

 public partial class Category
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int? ParentID { get; set; }
    public bool IsDeleted { get; set; }
    public virtual ICollection<Product> Products { get; set; }
    public virtual ICollection<CategoryTrans> CategoryTrans { get; set; }
}

 public class ISO_Languages
{
    public int ID { get; set; }
    public string code { get; set; }
    public bool IsEnabled { get; set; }
    public string name_en { get; set; }
    public string name_fr { get; set; }
    public string name_it { get; set; }
    public string name_de { get; set; }
    public string name_es { get; set; }
}

 public class CategoryTrans
{
    [Key, Column(Order = 1)]
    public int category_id { get; set; }
    [Key, Column(Order = 2)]
    public int language_id { get; set; }
    [ForeignKey("category_id")]
    public virtual Category categoryId { get; set; }
    [ForeignKey("language_id")]
    public virtual ISO_Languages languageId { get; set; }
    public string name { get; set; }
}

以下查询返回p.Category.CategoryTrans中的所有CategoryTrans,这意味着任何类别翻译

public static IQueryable<Product> ActiveProductsPerUser(BaseContext db, string userid, string culture)
    {

        var query = (from p in db.Products
                     join ct in db.CategoryTrans
                     on p.CategoryID equals ct.category_id
                     join l in db.ISO_Languages
                     on ct.language_id equals l.ID
                     where l.code.Substring(0, 2) == culture
                     select p);

        return query;
    }

我要做的是根据文化输入参数为每个产品过滤单一类别翻译。 类似的东西:

public static IQueryable<Product> ActiveProductsPerUser(BaseContext db, string userid, string culture)
    {
        var query = from p in db.Products
                     join ct in db.CategoryTrans
                     on p.CategoryID equals ct.category_id
                     join l in db.ISO_Languages
                     on ct.language_id equals l.ID
                     where l.code.Substring(0, 2) == culture
                     select new Product
                    {
                        ID = p.ID,
                        Name = p.Name,
                        Description = p.Description,
                        CategoryTrans = p.Category.CategoryTrans.Where(b => b.language_id.Equals(l.ID)).SingleOrDefault()
                    };
        return query;
    }

但收到错误:

  

无法在LINQ to Entities查询中构造实体或复杂类型“xyz.DAL.Product”。

正在寻找这个特定错误,我现在尝试投影到DTO:

public class ProductDTO
{
    public int? ID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public virtual CategoryTrans CategoryTrans { get; set; }
}

public static IQueryable<Product> ActiveProductsPerUser(BaseContext db, string userid, string culture)
    {
        var query = from p in db.Products
                     join ct in db.CategoryTrans
                     on p.CategoryID equals ct.category_id
                     join l in db.ISO_Languages
                     on ct.language_id equals l.ID
                     where l.code.Substring(0, 2) == culture
                     select new ProductDTO
                    {
                        ID = p.ID,
                        Name = p.Name,
                        Description = p.Description,
                        CategoryTrans = p.Category.CategoryTrans.Where(b => b.language_id.Equals(l.ID)).FirstOrDefault()
                    };
        return query.Cast<Product>();
    }

现在正在按预期工作,只返回到CategoryTrans所需的翻译。 因此查询现在可以工作但是将ProductDTO转换为所需的产品返回:

  

无法将类型'xyz.Controllers.ProductDTO'强制转换为'xyz.Models.Product'类型。 LINQ to Entities仅支持转换EDM原语或枚举类型。

我无法找到此异常的解决方案。

3 个答案:

答案 0 :(得分:1)

即使您能够将ProductDTO投射到产品型号,EF也不会自动跟踪这些对象。

一种可能的解决方案可能是首先选择产品,然后迭代它们以分配所需的属性。

答案 1 :(得分:0)

在您的第一个(失败的)查询中,我相信选择可以替换为:

 select new Product
 {
     ID = p.ID,
     Name = p.Name,
     Description = p.Description,
     CategoryTrans = ct
 };

可能会有效。

否则,你无法施放&lt;&gt;从一种对象类型到另一种对象类型,除非它们具有基本/派生关系。否则,您需要转换它们:

在产品DTO中,添加:

替换:

 return query.Cast<Product>();

使用:

 return  query.Select(p=> new Product 
            {
              ID = p.ID,
              Name = p.Name,
              Description = p.Description,
              CategoryTrans = p.CategoryTrans
              };   

更新: 好吧,让我们尝试不同的东西。 删除查询中的选择,只需使用p对象:

public static IQueryable<Product> ActiveProductsPerUser(BaseContext db,
                                                        string userid, string culture)
{
    var query = from p in db.Products
                 join ct in db.CategoryTrans
                 on p.CategoryID equals ct.category_id
                 join l in db.ISO_Languages
                 on ct.language_id equals l.ID
                 where l.code.Substring(0, 2) == culture;
    return query;
}

CategoryTrans属性保留为null,但它将引导您完成此操作以及查询的其他操作。当你走到尽头,并且实际上正在处理结果时,请拔出p.Category.CategoryTrans.Where(b => b.language_id.Equals(l.ID)).FirstOrDefault()以获得CategoryTrans

答案 2 :(得分:0)

我找不到

的答案
  

实体或复杂类型&#39; xyz.DAL.Product&#39;不能在LINQ to Entities查询中构造。

错误。我最终通过添加

解决了这个问题
CATEGORY_LAUNCHER

到产品型号类,负责显示本地化的类别名称,并将过滤移动到ViewModel,设置两个嵌套的foreach循环,返回一个新的完全本地化产品列表:

[NotMapped]
public virtual string LocalizedCategoryName { get; set; }

不知道它是最佳还是唯一的方式,但按预期工作。我现在可以使用简单查询并将返回的Product的IQueryable传递给排序和分页异步方法或其他任何方法。每当我完成时,结果将被分配给ViewModel.LocalizedProductList,其中getter负责最终过滤。感谢wonderbell的建议,一个可能的解决方案是首先选择产品,然后迭代它们以分配所需的属性。这就是为什么对他/她的帖子进行投票,即使它不能被视为问题的完整(甚至部分)解决方案。