【问题标题】:Select query with subquery that can return List<string>选择带有可以返回 List<string> 的子查询的查询
【发布时间】:2019-06-18 06:43:53
【问题描述】:

我有两个表:产品和产品图片

我正在尝试编写一个查询,以返回产品,并为每个产品提供一个关联但不断收到错误的图像名称列表(如下所示)。

实体看起来像这样:

public class ProductDto
{
    public int Id { get; set; }

    public string Name { get; set; }

    public long ProductNumber { get; set; }

    public decimal? Size { get; set; }

    public string SizeMeasurement { get; set; }

    public decimal? Pack { get; set; }

    public List<string> PhotoFileNames { get; set; }
}

此处显示出错的查询:

var query = from p in _productRepository.GetAll()
        let PhotoFileNames =  _productPhotoMapRepository.GetAll().DefaultIfEmpty()
            .Where(e => e.ProductId == p.Id).Select(e => e.FileName).ToList()
    where
    (string.IsNullOrWhiteSpace(input.Filter) || p.Name.Contains(input.Filter))
    select new
    {
        p.Id,
        p.ProductNumber,
        p.Name,
        p.Size,
        p.SizeMeasurement,
        p.Pack,
//I've also tried doing this but get same error:
//PhotoFileNames = _productPhotoMapRepository.GetAll().DefaultIfEmpty()
//                     .Where(e => e.ProductId == p.Id).Select(e => e.FileName).ToList()
        PhotoFileNames
    };

    var productList = await query.ToListAsync();

我收到的错误是:

System.ArgumentException: Expression of type 'System.Collections.Generic.IAsyncEnumerable`1[System.String]' cannot be used for parameter of type 'System.Collections.Generic.IEnumerable`1[System.String]' of method 'System.Collections.Generic.List`1[System.String] ToList[String](System.Collections.Generic.IEnumerable`1[System.String])'
Parameter name: arg0
   at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index)
   at System.Linq.Expressions.Expression.Call(MethodInfo method, Expression arg0)
   at System.Linq.Expressions.MethodCallExpression1.Rewrite(Expression instance, IReadOnlyList`1 args)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalEntityQueryableExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitAndConvert[T](ReadOnlyCollection`1 nodes, String callerName)
   at Remotion.Linq.Parsing.RelinqExpressionVisitor.VisitNew(NewExpression expression)
   at System.Linq.Expressions.NewExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalEntityQueryableExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)

出于性能原因,我试图避免使用 for 循环。如果我完全省略 PhotoFileNames,产品返回时不会出现任何问题。

获得每个产品的预期结果以及存储在不同 sql 表中的所有图像文件名的正确方法是什么?

编辑:添加了数据库上下文和模型类

public class Product
    {
        public int Id { get; set; } //Aka productId

        public string Name { get; set; }

        public long ProductNumber { get; set; }

        public decimal? Size { get; set; }

        public string SizeMeasurement { get; set; }

        public decimal? Pack { get; set; }
    }

       public class ProductPhotoMap 
        {
           public virtual long ProductPhotoId {get;set;}

            public virtual int DisplayOrder { get; set; }

            public virtual bool IsDefault { get; set; }     

            public virtual int ProductId { get; set; }
            public Product Product { get; set; }

            public virtual string FileName { get; set; }

        }

在我的上下文中:

    public virtual DbSet<Product> Products { get; set; }

    public virtual DbSet<ProductPhotoMap> ProductPhotoMappings { get; set; }

【问题讨论】:

  • 为什么是ToList()?你试过没有它吗?
  • @haim770 试了一下,发现一个新错误:System.InvalidCastException: Unable to cast object of type 'SelectEnumerableAsyncIterator2[Microsoft.EntityFrameworkCore.Storage.ValueBuffer,System.String]' to type 'System.Linq.IQueryable1[System.String]'。
  • 您的Product Image 模特在哪里? ProductPhotoDto 是那个模特吗?
  • 请在问题中包含您的ProductProductImage 模型类,这样很容易回答。
  • 问题,像往常一样,在你的回购中,坦率地说,它看起来一般都坏了。如果您想支持进一步查询,GetAll() 不应该是原子的。无论如何,我们需要查看代码才能发现问题。

标签: linq asp.net-core linq-to-entities entity-framework-core


【解决方案1】:

.ToListAsync() 不返回 List&lt;string&gt;。您可以更新属性,也可以非异步使用.ToList()

【讨论】:

  • 如果我确实做到了 var products = query.ToList() ,它确实有效。有没有办法异步执行此操作,或者这是唯一的选择?
  • 你意识到列表已经在内存中实现了对吧?尝试异步执行此操作基本上没有任何好处。
【解决方案2】:

您的整个查询完全混乱。所以很难猜出你真正想要什么。但我假设您可能想要以下内容:

所以首先更新你的Product 类如下:

public class Product
{
    public int Id { get; set; } //Aka productId

    public string Name { get; set; }

    public long ProductNumber { get; set; }

    public decimal? Size { get; set; }

    public string SizeMeasurement { get; set; }

    public decimal? Pack { get; set; }


    public ICollection<ProductPhotoMap> ProductPhotoMaps {get; set;}
}

然后编写查询如下:

var query = _productRepository.GetAll().Select(p => new ProductDto
       {
        Id = p.Id,
        ProductNumber = p.ProductNumber,
        Name = p.Name,
        Size = p.Size,
        SizeMeasurement = p.SizeMeasurement,
        Pack = p.Pack,
        PhotoFileNames = p.ProductPhotoMaps.Select(pp => pp.FileName).ToList()
    });

If(!string.IsNullOrWhiteSpace(input.Filter))
{
   query.Where(p => p.Name.Contains(input.Filter))
}

var productList = await query.ToListAsync();

【讨论】:

  • 现在试试这个。会告诉你它是否有效:) 谢谢!
  • 哦!我忘记将查询投射到ProductDto。请使用最新版本的答案。
  • 我按照建议添加了集合,但在尝试执行此 ToListAsync() 时仍然收到上述相同的错误,但如果我只是将其设为 var productList = query.ToList() 它就可以了。不知道我明白为什么会这样。
  • 哦!您的方法缺少async Task&lt;List&lt;ProductDto&gt;&gt;。请将返回类型 List&lt;ProductDto&gt; 替换为 async Task&lt;List&lt;ProductDto&gt;&gt;
  • @Drewskis 你明白你的错误了吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-26
  • 2013-12-26
  • 1970-01-01
  • 2019-12-22
相关资源
最近更新 更多