question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

IQueryable - TryFirst (async) -- Replacement for .FirstOrDefaultAsync() -- Is this helpful for a PR?

See original GitHub issue

Hello all,

I am new to this library, I am working with EFCore. In my scenerio I am working with IQueryable<T>.

I wanted a method like .FirstOrDefaultAsync(), because when I used .FirstOrDefaultAsync(), my return object was a pain, and looked like: Result<Maybe<TEntity?>, Error> , the nullable ? was giving me warnings in code.

I saw the methods TryFirst and TryLast - success I thought! But then I realized that these are not async, and do not use IQueryable

I created these methods for async and IQueryable:

    public static async Task<Maybe<T>> TryFirstAsync<T>(
        this IQueryable<T> source,
        CancellationToken cancellationToken = default)
    {
        var firstOrNull = await source.FirstOrDefaultAsync(cancellationToken);

        if (firstOrNull == null)
        {
            return Maybe<T>.None;
        }

        return Maybe<T>.From(firstOrNull);
    }

    public static async Task<Maybe<T>> TryFirstAsync<T>(
        this IQueryable<T> source,
        Func<T, bool> predicate,
        CancellationToken cancellationToken = default)
    {
        var firstOrEmpty = source.AsEnumerable()
            .Where(predicate)
            .Take(1)
            .AsQueryable();

        var firstOrNull = await firstOrEmpty.FirstOrDefaultAsync(cancellationToken);

        if (firstOrNull == null)
        {
            return Maybe<T>.None;
        }

        return Maybe<T>.From(firstOrNull);
    }


Note

Note: I realize that we do not use the Async suffix, however, using the suffix made things must easier, because without the suffix, the method would default to the IEnumerable<T> version, when I wanted to use the IQueryable<T> version.

Question

Is this helpful at all?

What should I do to replace IQueryable<T>.FirstOrDefaultAsync() in the future if this code is not helpful?

Issue Analytics

  • State:open
  • Created 10 months ago
  • Reactions:1
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
vkhorikovcommented, Dec 13, 2022

We can add these 2 extension methods if we don’t have them yet. Async postfix is fine to make it consistent with EF Core.

Regarding your second overload: please use @maxime-poulain 's version. This code:

var firstOrEmpty = source.AsEnumerable()
            .Where(predicate)
            .Take(1)
            .AsQueryable();

doesn’t work because converting the source to IEnumerable with AsEnumerable() will prompt EF Core to load the whole set of items and then do the filtration in-memory, which defeats the purpose of using IQueriable.

1reaction
maxime-poulaincommented, Dec 7, 2022

Lucian Wischik, who worked on the compiler for async/await pattern is clear:

I/O bound operations should always be asynchronous.

So everyting you say regarding having API with Task returning method when the input is an IQueryable is right. https://youtu.be/OpOaiz4mNP0?t=466 (The guy himself explains it there if you are interessted).

BTW FirstOrDefaultAsync has an overload that takes an Expression. You can have

        public static async Task<Maybe<T>> TryFirstAsync<T>(
            this IQueryable<T> source,
            Expression<Func<T, bool>> predicate,
            CancellationToken cancellationToken = default)
        {
            var firstOrNull = await source.FirstOrDefaultAsync(predicate, cancellationToken);

            if (firstOrNull == null)
            {
                return Maybe<T>.None;
            }

            return Maybe<T>.From(firstOrNull);
        }
    // Usage : IQuery<string> query = XXX;
    // var item = await query.TryFirstAsync(x => x == "hello");
Read more comments on GitHub >

github_iconTop Results From Across the Web

Issues · vkhorikov/CSharpFunctionalExtensions
IQueryable - TryFirst (async) -- Replacement for .FirstOrDefaultAsync() -- Is this helpful for a PR? #473 opened on Dec 1, 2022 by jeffward01....
Read more >
What do I replace IQueryable with for Async operations?
At one point, I decide that making action methods asynchronous is a good idea, so I try the following: await _queryService.QueryProject(prj).
Read more >
QueryableExtensions.FirstOrDefaultAsync Method
Asynchronously returns the first element of a sequence, or a default value if the sequence contains no elements.
Read more >
EntityFrameworkQueryableExten...
Asynchronously returns the first element of a sequence that satisfies a specified condition or a default value if no such element is found....
Read more >
c# - Is repository pattern violated while using IQueryable ...
1 Answer 1 ; public ProductController (ILogger<ProductController> logger, IMapper mapper) : base(logger, mapper) ; public async Task<IActionResult> ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found