【问题标题】:Confused About Why I have no extension methods available对为什么我没有可用的扩展方法感到困惑
【发布时间】:2021-10-19 14:05:01
【问题描述】:

我正在实施工作单元模式 (不是我的选择,我知道它被某些人视为反模式)。 我遇到了一个我不完全理解的情况。

我的通用回购构造函数:

this.context = context;
this.dbSet = context.Set<T>();

通用方法:

  public virtual async Task<IEnumerable<T>> All()
    {
        return await dbSet.ToListAsync();
    }

我用它:

  var languages = await _unitOfWork.Languages.All();
        languages = languages.OrderBy(x => x.Order);

如上所示,我需要下一行以便使用 OrderBy, 我不明白为什么。

第二个问题是,ToListAsync 假设返回一个列表,为什么我会得到一个 IENUMARABLE?

【问题讨论】:

  • ListIEnumerable 的实现。
  • 2.因为你是这样写的 (All()) ... 1. 显然你不能使用 _unitOfWork.Languages.All().OrderBy(x =&gt; x.Order) 因为 All 返回 Task&lt;T&gt;
  • 您不必“下线”,但All 返回的是Task,因此您需要先await 它才能让IEnumerable&lt;T&gt; 工作和。 await 直到 All 可以用括号括起来,然后你可以从那里 OrderBy
  • 因为await ...你可能会使用var languages = (await _unitOfWork.Languages.All().)OrderBy(x =&gt; x.Order);
  • 您可能正在使用另一个ToListAsync?据我了解,您想从EntityFramework.dll 使用ToListAsync,在这种情况下,您应该检查对EnityFramework.dll 的依赖并检查是否使用System.Data.Entity,其中扩展方法是。

标签: c# asp.net-core asynchronous .net-core


【解决方案1】:

第二个问题是,ToListAsync 假设返回一个列表,为什么我会得到一个 IENUMARABLE?

ListIEnumerable 的实现。检查What does it mean to "program to an interface"?

如上所示,我需要下一行才能使用 OrderBy,我不知道为什么。

_unitOfWork.Languages.All() 返回一个Task,你应该得到它的解包结果IEnumerable 来应用OrderBy

要使这项工作按您的预期进行,您应该在等待的结果上应用OrderBy

(await _unitOfWork.Languages.All()).OrderBy(x => x.Order);

【讨论】:

    【解决方案2】:

    将它们放在同一行上的困惑似乎在于它如何应用await。这应该可以正常工作:

    var languages = (await _unitOfWork.Languages.All()).OrderBy(x => x.Order);
    

    您需要这样做,因为您的 All 函数返回 TaskOrderBy 不是。

    此外,您可能一开始就不想打电话给.ToListAsync(),那只是一个SELECT *,没有任何限制或where子句,它可能不会一直是“世界末日”,但通常会对您的表现极为不利。

    关于你关于为什么它返回IEnumerable&lt;T&gt; 的第二个问题是因为List&lt;T&gt; 实现IEnumerable&lt;T&gt; 并且你的函数签名表明它返回IEnumerable&lt;T&gt;

    public virtual async Task<IEnumerable<T>> All()
    

    我强烈建议您不要处理 .ToListAsyncIEnumerable&lt;T&gt;,而不要管它,让 IQueryable&lt;T&gt; 对数据库进行适当的工作。

    编辑:在 cmets 中被问到为什么使用 IQueryable&lt;T&gt; 很重要。答案是因为使用.Where.Any() 等...针对IQueryable 将塑造针对数据库的基础查询。

    例如,假设您要查找具有Id123 的单个实体。如果您将.ToListAsync() 保留而没有任何其他修改,它将把数据库中的每一行都拉回内存中的程序,然后迭代每一行以寻找那一行。

    相反,如果您使用IQueryable&lt;T&gt; - 在您应用.FirstOrDefault(e =&gt; e.Id == 123) 时,它将被应用到数据库中,并且它会像SELECT TOP(1) * FROM MyEntity WHERE [Id] = 123 一样应用 - 撤回单个行而不是存在的每一行。

    EDIT2:请注意,这也适用于投影。这意味着像.Select(e =&gt; new { FullName = e.FirstName + " " + e.LastName, State = e.Address.State}) 这样的东西只会拉出那两列而不是所有列和您包含的任何导航属性。在.ToList().ToListAsync 之后执行此操作将取而代之拉回所有列/实体并迭代它们以创建一组全新的其他实体。这可能会导致两种方法之间存在巨大的 CPU/内存差异。

    【讨论】:

    • IQueryable 如何更好?
    • @Kosta - 我已经编辑了我的答案以阐述IQueryable&lt;T&gt;
    • 很好的答案,我是 C# 新手,学到了一些新东西 :)
    • 非常详细的回答,谢谢!
    • @Kosta,如果您要返回IQueryable&lt;T&gt; - 那么不要为自己的“工作单元”实现而烦恼,因为DbContext 就是这样 - Unit of Work 的实现;)
    猜你喜欢
    • 2013-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多