IQueryable doesn't implement IDbAsyncEnumerable

May 22, 2014 at 12:53 PM
Edited May 22, 2014 at 2:44 PM

Introduction

Entity Framework 6 introduced a set of extension methods that can be used to asynchronously execute a query. Examples of these methods include ToListAsync, FirstAsync, ForEachAsync, etc.

Whilst the async methods are only supported when running against an EF query, you may want to use them in your unit test when running against an in-memory test double of a DbSet.

In article Testing with your own test doubles is explained how to writing your own in-memory implementation of your context and DbSets.

Practical Problem

FakeDbSet.cs in the namespace Repository.Pattern.Ef6 provides an in-memory implementation of DbSet for testing purposes but lacks IDbAsyncEnumerable implementation. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations.

Solution

FakeDbSet must implement IDbAsyncEnumerable:
public abstract class FakeDbSet<TEntity> : DbSet<TEntity>, IDbSet<TEntity>, IQueryable, IEnumerable<TEntity>, IDbAsyncEnumerable<TEntity>  where TEntity : Entity, new()
{
    // ... Other methods...

    public IQueryProvider Provider
    {
         get { return new TestDbAsyncQueryProvider<TEntity>(_query.Provider); } 
    }
    
    IDbAsyncEnumerator<TEntity> IDbAsyncEnumerable<TEntity>.GetAsyncEnumerator()
    {
        return new TestDbAsyncEnumerator<TEntity>(_data.GetEnumerator());
    } 
}
The code for the classes TestDbAsyncQueryProvider<TEntity>, TestDbAsyncEnumerator<TEntity> and TestDbAsyncEnumerable<T> ( TestDbAsyncEnumerator<TEntity> depends on it) can be found here.
Coordinator
May 22, 2014 at 3:02 PM
Thanks, we'll review this, and most likely queue this up for the next release.
Marked as answer by lelong37 on 5/22/2014 at 8:02 AM
May 22, 2014 at 4:08 PM
lelong37 wrote:
Thanks, we'll review this, and most likely queue this up for the next release.
Thank you, lelong37.
Oct 7, 2014 at 12:47 AM
Edited Oct 7, 2014 at 12:51 AM
Hi Emperor_ming, lelong37, I've got the same issue around testing today, the source for the Test is more accurately
here
//_items, rather than data
        IDbAsyncEnumerator<TEntity> IDbAsyncEnumerable<TEntity>.GetAsyncEnumerator()
        {
            return new TestDbAsyncEnumerator<TEntity>(_items.GetEnumerator()); 
        } 
Oct 8, 2014 at 8:19 AM
OzBobWA wrote:
Hi Emperor_ming, lelong37, I've got the same issue around testing today, the source for the Test is more accurately
here
//_items, rather than data
        IDbAsyncEnumerator<TEntity> IDbAsyncEnumerable<TEntity>.GetAsyncEnumerator()
        {
            return new TestDbAsyncEnumerator<TEntity>(_items.GetEnumerator()); 
        } 
Hi OzBobWA. Let me know if I can help you. It's been a while since I dealt with this problem, but count on me.

EM
Oct 15, 2014 at 2:43 AM
HI Emperor_ming,
your suggested additions and my correction are working fine - i'm happy with the test coverage. there's a gap about Linq to Sql conversion against a 'real' DB, and some errors not getting picked up with 'false positives' but i'll work on them.
If only I knew how to use Git - I'd make a 'pull request'(?) to put your code in the next version .....