关于 asp.net mvc:Linq 过滤实体的集合最终出现在 LINQ to Entities 转换错误

Linq filtering entity's collection ends up in LINQ to Entities casting error

ASPNET MVC5 网络应用程序

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

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

型号:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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 中的 ALL CategoryTrans,即任何类别翻译

1
2
3
4
5
6
7
8
9
10
11
12
13
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;
    }

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
    }

但出现错误:

The entity or complex type 'xyz.DAL.Product' cannot be constructed in a LINQ to Entities query.

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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 转换为所需的产品返回:

Unable to cast the type 'xyz.Controllers.ProductDTO' to type 'xyz.Models.Product'. LINQ to Entities only supports casting EDM primitive or enumeration types.

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


即使您能够将 ProductDTO 转换为 Product 模型,EF 也不会自动跟踪这些对象。

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


我找不到

的答案

The entity or complex type 'xyz.DAL.Product' cannot be constructed in a LINQ to Entities query.

错误。我最终通过添加一个

解决了这个问题

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
private List<Product> _LocalizedProductList = new List<Product>();

public List<Product> LocalizedProductList
    {
        get
        {
            HttpUtilities HttpHelper = new HttpUtilities();
            string culture = HttpHelper.getFullCulture();
            int IsoCode = GenericUtilities.getIsoID(culture, db);
            List<Product> localized = new List<Product>();

            foreach (Product p in _LocalizedProductList)
            {
                foreach (CategoryTrans c in p.Category.CategoryTrans)
                {
                    if (c.language_id.Equals(IsoCode))
                    {
                        Product x = new Product
                        {
                            ID = p.ID,
                            LocalizedCategoryName = c.name,
                            DateCreated = p.DateCreated,
                            DateExpire = p.DateExpire,
                            DateLastModified = p.DateLastModified,
                            Name = p.Name,
                            Description = p.Description,
                            IsApproved = p.IsApproved,
                            IsDeleted = p.IsDeleted,
                            ProductImages = p.ProductImages,
                            User = p.User
                        };
                        localized.Add(x);
                    };
               }
        }
        return localized;
    }

    set { _LocalizedProductList = value; }
}

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


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

1
2
3
4
5
6
7
 select new Product
 {
     ID = p.ID,
     Name = p.Name,
     Description = p.Description,
     CategoryTrans = ct
 };

这可能有效。

否则,您不能将<>从一种对象类型转换为另一种对象类型,除非它们具有基础/派生关系。否则,您需要转换它们:

在产品 DTO 中,添加:

替换:

1
 return query.Cast<Product>();

与:

1
2
3
4
5
6
7
 return  query.Select(p=> new Product
            {
              ID = p.ID,
              Name = p.Name,
              Description = p.Description,
              CategoryTrans = p.CategoryTrans
              };

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

1
2
3
4
5
6
7
8
9
10
11
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 属性为空,但它会帮助您完成此操作以及查询的其他操作。当你走到尽头,并且实际上正在对结果进行处理时,然后拉出 p.Category.CategoryTrans.Where(b => b.language_id.Equals(l.ID)).FirstOrDefault() 以获取 CategoryTrans