This project is read-only.

 

Async Query & Save API Review

The purpose of API Review meetings is to go over new API surface one class/member at a time to ensure we have a consistent and high quality API. We look at how classes are structured, which members are public as well as the names of classes, members and parameters.

General Review

We've verified that all Async methods have two overloads, one that takes a CancellationToken and one that does not. The only exceptions to this are classes that are generally only used by our infrastructure where we don’t need an overload without a cancellation token.

Save API

System.Data.Entity.DbContext

  • Task<Int32> SaveChangesAsync()
  • Task<Int32> SaveChangesAsync(CancellationToken cancellationToken)

No changes required to this API.

Query API

System.Data.Entity.DbSetExtensions

  • Task<TEntity> FindAsync<TEntity>(IDbSet<TEntity> set, Object[] keyValues)

System.Data.Entity.DbSet

  • Task<Object> FindAsync(Object[] keyValues)
  • Task<Object> FindAsync(CancellationToken cancellationToken, Object[] keyValues)

System.Data.Entity.IDbSet<TEntity>

  • Task<TEntity> FindAsync(CancellationToken cancellationToken, Object[] keyValues)

System.Data.Entity.DbSet<TEntity>

  • Task<TEntity> FindAsync(CancellationToken cancellationToken, Object[] keyValues)

Do we really want to add a member to the IDbSet interface which will require anyone using it to update their code to compile against EF6? We think a significant number of developers are implementing this interface for testing. It doesn't affect folks using a mocking framework, but we do think a number of folks have coded up a fake implementation for IDbSet.

Some other options we discussed were:

  • Adding an IAsyncDbSet interface that extends IDbSet and adds just the async methods.
  • Making the async methods extension methods on IDbSet - similar to how we do Include(lambda). The extension method would check for DbSet, then fall back to dynamically calling FindAsync and finally fall back to calling Find wrapped in a Task.
  • Just make them instance methods on DbSet and not make them available on IDbSet.

We ultimately decided to leave it as-is. Introducing a second interface just seemed confusing and hard to understand and the other two options make it too difficult for folks who want to test code that does call FindAsync.

[Action Item] We will publish some guidance around how to easily implement FindAsync (wrapping Find up in a Task).

System.Data.Entity.IQueryableExtensions

  • Task<Nullable<Double>> AverageAsync(IQueryable<Nullable<Int32>> source, CancellationToken cancellationToken)
  • Task<Double> AverageAsync(IQueryable<Int64> source)
  • Task<Double> AverageAsync(IQueryable<Int64> source, CancellationToken cancellationToken)
  • Task<Nullable<Double>> AverageAsync(IQueryable<Nullable<Int64>> source)
  • Task<Nullable<Double>> AverageAsync(IQueryable<Nullable<Int64>> source, CancellationToken cancellationToken)
  • Task<Single> AverageAsync(IQueryable<Single> source)
  • Task<Single> AverageAsync(IQueryable<Single> source, CancellationToken cancellationToken)
  • Task<Nullable<Single>> AverageAsync(IQueryable<Nullable<Single>> source)
  • Task<Nullable<Single>> AverageAsync(IQueryable<Nullable<Single>> source, CancellationToken cancellationToken)
  • Task<Double> AverageAsync(IQueryable<Double> source)
  • Task<Double> AverageAsync(IQueryable<Double> source, CancellationToken cancellationToken)
  • Task<Nullable<Double>> AverageAsync(IQueryable<Nullable<Double>> source)
  • Task<Nullable<Double>> AverageAsync(IQueryable<Nullable<Double>> source, CancellationToken cancellationToken)
  • Task<Decimal> AverageAsync(IQueryable<Decimal> source)
  • Task<Decimal> AverageAsync(IQueryable<Decimal> source, CancellationToken cancellationToken)
  • Task<Nullable<Decimal>> AverageAsync(IQueryable<Nullable<Decimal>> source)
  • Task<Nullable<Decimal>> AverageAsync(IQueryable<Nullable<Decimal>> source, CancellationToken cancellationToken)
  • Task<Double> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Int32>> selector)
  • Task<Double> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Int32>> selector, CancellationToken cancellationToken)
  • Task<Nullable<Double>> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Int32>>> selector)
  • Task<Nullable<Double>> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Int32>>> selector, CancellationToken cancellationToken)
  • Task<Double> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Int64>> selector)
  • Task<Double> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Int64>> selector, CancellationToken cancellationToken)
  • Task<Nullable<Double>> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Int64>>> selector)
  • Task<Nullable<Double>> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Int64>>> selector, CancellationToken cancellationToken)
  • Task<Single> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Single>> selector)
  • Task<Single> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Single>> selector, CancellationToken cancellationToken)
  • Task<Nullable<Single>> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Single>>> selector)
  • Task<Nullable<Single>> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Single>>> selector, CancellationToken cancellationToken)
  • Task<Double> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Double>> selector)
  • Task<Double> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Double>> selector, CancellationToken cancellationToken)
  • Task<Nullable<Double>> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Double>>> selector)
  • Task<Nullable<Double>> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Double>>> selector, CancellationToken cancellationToken)
  • Task<Decimal> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Decimal>> selector)
  • Task<Decimal> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Decimal>> selector, CancellationToken cancellationToken)
  • Task<Nullable<Decimal>> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Decimal>>> selector)
  • Task<Nullable<Decimal>> AverageAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Decimal>>> selector, CancellationToken cancellationToken)
  • Task<Boolean> AllAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate, CancellationToken cancellationToken)
  • Task<Int32> CountAsync<TSource>(IQueryable<TSource> source)
  • Task<Int32> CountAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken)
  • Task<Int32> CountAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate)
  • Task<Int32> CountAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate, CancellationToken cancellationToken)
  • Task<Int64> LongCountAsync<TSource>(IQueryable<TSource> source)
  • Task<Int64> LongCountAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken)
  • Task<Int64> LongCountAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate)
  • Task<Int64> LongCountAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate, CancellationToken cancellationToken)
  • Task<TSource> MinAsync<TSource>(IQueryable<TSource> source)
  • Task<TSource> MinAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken)
  • Task<TResult> MinAsync<TSource, TResult>(IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector)
  • Task<TResult> MinAsync<TSource, TResult>(IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector, CancellationToken cancellationToken)
  • Task<TSource> MaxAsync<TSource>(IQueryable<TSource> source)
  • Task<TSource> MaxAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken)
  • Task<TResult> MaxAsync<TSource, TResult>(IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector)
  • Task<TResult> MaxAsync<TSource, TResult>(IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector, CancellationToken cancellationToken)
  • Task<Int32> SumAsync(IQueryable<Int32> source)
  • Task<Int32> SumAsync(IQueryable<Int32> source, CancellationToken cancellationToken)
  • Task<Nullable<Int32>> SumAsync(IQueryable<Nullable<Int32>> source)
  • Task<Nullable<Int32>> SumAsync(IQueryable<Nullable<Int32>> source, CancellationToken cancellationToken)
  • Task<Int64> SumAsync(IQueryable<Int64> source)
  • Task<Int64> SumAsync(IQueryable<Int64> source, CancellationToken cancellationToken)
  • Task<Nullable<Int64>> SumAsync(IQueryable<Nullable<Int64>> source)
  • Task<Nullable<Int64>> SumAsync(IQueryable<Nullable<Int64>> source, CancellationToken cancellationToken)
  • Task<Single> SumAsync(IQueryable<Single> source)
  • Task<Single> SumAsync(IQueryable<Single> source, CancellationToken cancellationToken)
  • Task<Nullable<Single>> SumAsync(IQueryable<Nullable<Single>> source)
  • Task<Nullable<Single>> SumAsync(IQueryable<Nullable<Single>> source, CancellationToken cancellationToken)
  • Task<Double> SumAsync(IQueryable<Double> source)
  • Task<Double> SumAsync(IQueryable<Double> source, CancellationToken cancellationToken)
  • Task<Nullable<Double>> SumAsync(IQueryable<Nullable<Double>> source)
  • Task<Nullable<Double>> SumAsync(IQueryable<Nullable<Double>> source, CancellationToken cancellationToken)
  • Task<Decimal> SumAsync(IQueryable<Decimal> source)
  • Task<Decimal> SumAsync(IQueryable<Decimal> source, CancellationToken cancellationToken)
  • Task<Nullable<Decimal>> SumAsync(IQueryable<Nullable<Decimal>> source)
  • Task<Nullable<Decimal>> SumAsync(IQueryable<Nullable<Decimal>> source, CancellationToken cancellationToken)
  • Task<Int32> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Int32>> selector)
  • Task<Int32> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Int32>> selector, CancellationToken cancellationToken)
  • Task<Nullable<Int32>> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Int32>>> selector)
  • Task<Nullable<Int32>> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Int32>>> selector, CancellationToken cancellationToken)
  • Task<Int64> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Int64>> selector)
  • Task<Int64> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Int64>> selector, CancellationToken cancellationToken)
  • Task<Nullable<Int64>> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Int64>>> selector)
  • Task<Nullable<Int64>> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Int64>>> selector, CancellationToken cancellationToken)
  • Task<Single> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Single>> selector)
  • Task<Single> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Single>> selector, CancellationToken cancellationToken)
  • Task<Nullable<Single>> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Single>>> selector)
  • Task<Nullable<Single>> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Single>>> selector, CancellationToken cancellationToken)
  • Task<Double> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Double>> selector)
  • Task<Double> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Double>> selector, CancellationToken cancellationToken)
  • Task<Nullable<Double>> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Double>>> selector)
  • Task<Nullable<Double>> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Double>>> selector, CancellationToken cancellationToken)
  • Task<Decimal> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Decimal>> selector)
  • Task<Decimal> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Decimal>> selector, CancellationToken cancellationToken)
  • Task<Nullable<Decimal>> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Decimal>>> selector)
  • Task<Nullable<Decimal>> SumAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Nullable<Decimal>>> selector, CancellationToken cancellationToken)
  • Task<Double> AverageAsync(IQueryable<Int32> source)
  • Task<Double> AverageAsync(IQueryable<Int32> source, CancellationToken cancellationToken)
  • Task<Nullable<Double>> AverageAsync(IQueryable<Nullable<Int32>> source)
  • Task LoadAsync(IQueryable source)
  • Task LoadAsync(IQueryable source, CancellationToken cancellationToken)
  • Task ForEachAsync(IQueryable source, Action<Object> action)
  • Task ForEachAsync(IQueryable source, Action<Object> action, CancellationToken cancellationToken)
  • Task ForEachAsync<T>(IQueryable<T> source, Action<T> action)
  • Task ForEachAsync<T>(IQueryable<T> source, Action<T> action, CancellationToken cancellationToken)
  • Task<List<T>> ToListAsync<T>(IQueryable source)
  • Task<List<T>> ToListAsync<T>(IQueryable source, CancellationToken cancellationToken)
  • Task<List<T>> ToListAsync<T>(IQueryable<T> source)
  • Task<List<T>> ToListAsync<T>(IQueryable<T> source, CancellationToken cancellationToken)
  • Task<T[]> ToArrayAsync<T>(IQueryable<T> source)
  • Task<T[]> ToArrayAsync<T>(IQueryable<T> source, CancellationToken cancellationToken)
  • Task<Dictionary<TKey, TSource>> ToDictionaryAsync<TSource, TKey>(IQueryable<TSource> source, Func<TSource, TKey> keySelector)
  • Task<Dictionary<TKey, TSource>> ToDictionaryAsync<TSource, TKey>(IQueryable<TSource> source, Func<TSource, TKey> keySelector, CancellationToken cancellationToken)
  • Task<Dictionary<TKey, TSource>> ToDictionaryAsync<TSource, TKey>(IQueryable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  • Task<Dictionary<TKey, TSource>> ToDictionaryAsync<TSource, TKey>(IQueryable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
  • Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TSource, TKey, TElement>(IQueryable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
  • Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TSource, TKey, TElement>(IQueryable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, CancellationToken cancellationToken)
  • Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TSource, TKey, TElement>(IQueryable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
  • Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TSource, TKey, TElement>(IQueryable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
  • Task<TSource> FirstAsync<TSource>(IQueryable<TSource> source)
  • Task<TSource> FirstAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken)
  • Task<TSource> FirstAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate)
  • Task<TSource> FirstAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate, CancellationToken cancellationToken)
  • Task<TSource> FirstOrDefaultAsync<TSource>(IQueryable<TSource> source)
  • Task<TSource> FirstOrDefaultAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken)
  • Task<TSource> FirstOrDefaultAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate)
  • Task<TSource> FirstOrDefaultAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate, CancellationToken cancellationToken)
  • Task<TSource> SingleAsync<TSource>(IQueryable<TSource> source)
  • Task<TSource> SingleAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken)
  • Task<TSource> SingleAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate)
  • Task<TSource> SingleAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate, CancellationToken cancellationToken)
  • Task<TSource> SingleOrDefaultAsync<TSource>(IQueryable<TSource> source)
  • Task<TSource> SingleOrDefaultAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken)
  • Task<TSource> SingleOrDefaultAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate)
  • Task<TSource> SingleOrDefaultAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate, CancellationToken cancellationToken)
  • Task<Boolean> ContainsAsync<TSource>(IQueryable<TSource> source, TSource item)
  • Task<Boolean> ContainsAsync<TSource>(IQueryable<TSource> source, TSource item, CancellationToken cancellationToken)
  • Task<Boolean> AnyAsync<TSource>(IQueryable<TSource> source)
  • Task<Boolean> AnyAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken)
  • Task<Boolean> AnyAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate)
  • Task<Boolean> AnyAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate, CancellationToken cancellationToken)
  • Task<Boolean> AllAsync<TSource>(IQueryable<TSource> source, Expression<Func<TSource, Boolean>> predicate)
  • IQueryable AsStreaming(this IQueryable source)
  • IQueryable<T> AsStreaming(this IQueryable<T> source)

Do we want to standardize on using TSource for generic argument name? We should be consistent with non-async versions from the framework. There are some places where this is not the case at the moment (i.e. ToList is TSource in the framework but ToListAsync is T).

[Action Item] Need to review and standardize these as part of XML doc polish.

We have ForEachAsync which works well but is a little complicated. Do we want ToEnumerableAsync which would give an enumerator that can then be used in a standard foreach loop? We don't need it now and we can always add it in the future if we see folks wanting it.

System.Data.Entity.Infrastructure.DbQuery

  • DbQuery AsStreaming()

System.Data.Entity.Infrastructure.DbQuery<TResult>

  • DbQuery<TResult> AsStreaming()

No changes required to this API.

Raw SQL API

System.Data.Entity.Database

  • Task<Int32> ExecuteSqlCommandAsync(String sql, Object[] parameters)
  • Task<Int32> ExecuteSqlCommandAsync(String sql, CancellationToken cancellationToken, Object[] parameters)

System.Data.Entity.Infrastructure.DbSqlQuery

  • DbSqlQuery AsStreaming()

System.Data.Entity.Infrastructure.DbSqlQuery<TEntity>

  • DbSqlQuery<TEntity> AsStreaming()

System.Data.Entity.Infrastructure.DbRawSqlQuery

  • Task ForEachAsync(Action<Object> action)
  • Task ForEachAsync(Action<Object> action, CancellationToken cancellationToken)
  • Task<List<T>> ToListAsync<T>()
  • Task<List<T>> ToListAsync<T>(CancellationToken cancellationToken)
  • DbRawSqlQuery AsStreaming()

System.Data.Entity.Infrastructure.DbRawSqlQuery<TElement>

  • Task ForEachAsync(Action<TElement> action)
  • Task ForEachAsync(Action<TElement> action, CancellationToken cancellationToken)
  • Task<List<TElement>> ToListAsync()
  • Task<List<TElement>> ToListAsync(CancellationToken cancellationToken)
  • Task<TElement[]> ToArrayAsync()
  • Task<TElement[]> ToArrayAsync(CancellationToken cancellationToken)
  • Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TKey>(Func<TElement, TKey> keySelector)
  • Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TKey>(Func<TElement, TKey> keySelector, CancellationToken cancellationToken)
  • Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TKey>(Func<TElement, TKey> keySelector, IEqualityComparer<TKey> comparer)
  • Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TKey>(Func<TElement, TKey> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
  • Task<Dictionary<TKey, TResult>> ToDictionaryAsync<TKey, TResult>(Func<TElement, TKey> keySelector, Func<TElement, TResult> elementSelector)
  • Task<Dictionary<TKey, TResult>> ToDictionaryAsync<TKey, TResult>(Func<TElement, TKey> keySelector, Func<TElement, TResult> elementSelector, CancellationToken cancellationToken)
  • Task<Dictionary<TKey, TResult>> ToDictionaryAsync<TKey, TResult>(Func<TElement, TKey> keySelector, Func<TElement, TResult> elementSelector, IEqualityComparer<TKey> comparer)
  • Task<Dictionary<TKey, TResult>> ToDictionaryAsync<TKey, TResult>(Func<TElement, TKey> keySelector, Func<TElement, TResult> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
  • Task<TElement> FirstAsync()
  • Task<TElement> FirstAsync(CancellationToken cancellationToken)
  • Task<TElement> FirstAsync(Func<TElement, Boolean> predicate)
  • Task<TElement> FirstAsync(Func<TElement, Boolean> predicate, CancellationToken cancellationToken)
  • Task<TElement> FirstOrDefaultAsync()
  • Task<TElement> FirstOrDefaultAsync(CancellationToken cancellationToken)
  • Task<TElement> FirstOrDefaultAsync(Func<TElement, Boolean> predicate)
  • Task<TElement> FirstOrDefaultAsync(Func<TElement, Boolean> predicate, CancellationToken cancellationToken)
  • Task<TElement> SingleAsync()
  • Task<TElement> SingleAsync(CancellationToken cancellationToken)
  • Task<TElement> SingleAsync(Func<TElement, Boolean> predicate)
  • Task<TElement> SingleAsync(Func<TElement, Boolean> predicate, CancellationToken cancellationToken)
  • Task<TElement> SingleOrDefaultAsync()
  • Task<TElement> SingleOrDefaultAsync(CancellationToken cancellationToken)
  • Task<TElement> SingleOrDefaultAsync(Func<TElement, Boolean> predicate)
  • Task<TElement> SingleOrDefaultAsync(Func<TElement, Boolean> predicate, CancellationToken cancellationToken)
  • Task<Boolean> ContainsAsync(TElement value)
  • Task<Boolean> ContainsAsync(TElement value, CancellationToken cancellationToken)
  • Task<Boolean> AnyAsync()
  • Task<Boolean> AnyAsync(CancellationToken cancellationToken)
  • Task<Boolean> AnyAsync(Func<TElement, Boolean> predicate)
  • Task<Boolean> AnyAsync(Func<TElement, Boolean> predicate, CancellationToken cancellationToken)
  • Task<Boolean> AllAsync(Func<TElement, Boolean> predicate)
  • Task<Boolean> AllAsync(Func<TElement, Boolean> predicate, CancellationToken cancellationToken)
  • Task<Int32> CountAsync()
  • Task<Int32> CountAsync(CancellationToken cancellationToken)
  • Task<Int32> CountAsync(Func<TElement, Boolean> predicate)
  • Task<Int32> CountAsync(Func<TElement, Boolean> predicate, CancellationToken cancellationToken)
  • Task<Int64> LongCountAsync()
  • Task<Int64> LongCountAsync(CancellationToken cancellationToken)
  • Task<Int64> LongCountAsync(Func<TElement, Boolean> predicate)
  • Task<Int64> LongCountAsync(Func<TElement, Boolean> predicate, CancellationToken cancellationToken)
  • Task<TElement> MinAsync()
  • Task<TElement> MinAsync(CancellationToken cancellationToken)
  • Task<TElement> MaxAsync()
  • Task<TElement> MaxAsync(CancellationToken cancellationToken)
  • DbRawSqlQuery<TElement> AsStreaming()

We've implemented an Async version of every method that is supported by LINQ to Entities and causes data to be retrieved immediately from the database.

Having a generic ToList on the non-generic DbRawSqlQuery is a bit strange. The developer would have to write:

context.Database.SqlQuery(typeof(Product), "SELECT * FROM Products").ToList<Product>()

But then they could have just written:

context.Database.SqlQuery<Product>("SELECT * FROM Products").ToList()

[Action Item] We should remove the generic on ToList and just make it return a non-generic list.

Developers need to remember to import the System.Data.Entity namespace for these methods to show up. Typically you don't have this namespace imported in the code that you would write queries in. Should we move them into the System.Linq namespace? No - we shouldn't hijack a namespace owned by another product. There may be other products that have Async versions too.

Change Tracker API

System.Data.Entity.Infrastructure.DbCollectionEntry

  • Task LoadAsync()
  • Task LoadAsync(CancellationToken cancellationToken)

System.Data.Entity.Infrastructure.DbCollectionEntry<TEntity, TElement>

  • Task LoadAsync()
  • Task LoadAsync(CancellationToken cancellationToken)

System.Data.Entity.Infrastructure.DbEntityEntry

  • Task<DbPropertyValues> GetDatabaseValuesAsync()
  • Task<DbPropertyValues> GetDatabaseValuesAsync(CancellationToken cancellationToken)

System.Data.Entity.Infrastructure.DbEntityEntry<TEntity>

  • Task<DbPropertyValues> GetDatabaseValuesAsync()
  • Task<DbPropertyValues> GetDatabaseValuesAsync(CancellationToken cancellationToken)

System.Data.Entity.Infrastructure.DbReferenceEntry

  • Task LoadAsync()
  • Task LoadAsync(CancellationToken cancellationToken)

System.Data.Entity.Infrastructure.DbReferenceEntry<TEntity, TProperty>

  • Task LoadAsync()
  • Task LoadAsync(CancellationToken cancellationToken)

[Action Item] We need to add ReloadAsync to DbEntityEntry and DbEntityEntry<Tentity>

Execution Strategy API

System.Data.Entity.Infrastructure.IExecutionStrategy

  • Task ExecuteAsync(Func<Task> taskFunc)
  • Task ExecuteAsync(Func<Task> taskFunc, CancellationToken cancellationToken)
  • Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> taskFunc)
  • Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> taskFunc, CancellationToken cancellationToken)

System.Data.Entity.Infrastructure.ExecutionStrategy

  • Task ExecuteAsync(Func<Task> taskFunc)
  • Task ExecuteAsync(Func<Task> taskFunc, CancellationToken cancellationToken)
  • Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> taskFunc)
  • Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> taskFunc, CancellationToken cancellationToken)

System.Data.Entity.Infrastructure.NonRetryingExecutionStrategy

  • Task ExecuteAsync(Func<Task> taskFunc)
  • Task ExecuteAsync(Func<Task> taskFunc, CancellationToken cancellationToken)
  • Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> taskFunc)
  • Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> taskFunc, CancellationToken cancellationToken)

[Action Item] The methods on IExecutionStrategy that don't take a CancellationToken can be changed to extension methods

  • They should go in the .Infrastrucutre sub-namespace. This makes them less discoverable but they are mostly just used by our stack anyway (and passing CancellationToken.None isn't so bad if you don't find them).

'taskFunc' is a strange parameter name

  • [Action Item] We'll rename them to match the non-async method parameter names. These may change when we API review the connection resilincy feature.

Infrastructure APIs

New Async Specific Classes

System.Data.Entity.Infrastructure.IDbAsyncEnumerable

  • IDbAsyncEnumerator GetAsyncEnumerator()

System.Data.Entity.Infrastructure.IDbAsyncEnumerable<out T>

  • IDbAsyncEnumerator<T> GetAsyncEnumerator()

System.Data.Entity.Infrastructure.IDbAsyncEnumerator

  • Task<bool> MoveNextAsync(CancellationToken cancellationToken)
  • object Current { get; }

System.Data.Entity.Infrastructure.IDbAsyncEnumerator<out T>

  • T Current { get; }

System.Data.Entity.Infrastructure.IDbAsyncEnumeratorExtensions

  • IDbAsyncEnumerator<TResult> Cast<TResult>(this IDbAsyncEnumerator source)
  • Task<bool> MoveNextAsync(this IDbAsyncEnumerator enumerator)

System.Data.Entity.Infrastructure.IDbAsyncQueryProvider

  • Task<object> ExecuteAsync(Expression expression,CancellationToken cancellationToken)
  • Task<TResult> ExecuteAsync<TResult>(Expression expression,CancellationToken cancellationToken)

System.Data.Entity.Infrastructure.IDbAsyncQueryProviderExtensions

  • Task<object> ExecuteAsync(this IDbAsyncQueryProvider provider, Expression expression)
  • Task<TResult> ExecuteAsync<TResult>(this IDbAsyncQueryProvider provider,Expression expression)

Should the private/internal classes be moved to Internal namespace (we've typically done this in the past)? No, we previously made the decision to change this practice and keep related components (both public and internal) in the same namespace.

Should we create a .Async sub-namespace for these components? We don't think it’s needed at this stage.

[Action Item] IDbAsyncEnumeratorExtensions and IDbAsyncQueryProviderExtensions can be made internal. We don't expect users to really interact with these interfaces.

Existing Classes

System.Data.Entity.Core.Objects.ObjectContext

  • Task<Int32> ExecuteStoreCommandAsync(String commandText, Object[] parameters)
  • Task<Int32> ExecuteStoreCommandAsync(String commandText, CancellationToken cancellationToken, Object[] parameters)
  • Task<ObjectResult<TElement>> ExecuteStoreQueryAsync<TElement>(String commandText, Object[] parameters)
  • Task<ObjectResult<TElement>> ExecuteStoreQueryAsync<TElement>(String commandText, CancellationToken cancellationToken, Object[] parameters)
  • Task<ObjectResult<TElement>> ExecuteStoreQueryAsync<TElement>(String commandText, ExecutionOptions executionOptions, Object[] parameters)
  • Task<ObjectResult<TElement>> ExecuteStoreQueryAsync<TElement>(String commandText, ExecutionOptions executionOptions, CancellationToken cancellationToken, Object[] parameters)
  • Task<ObjectResult<TElement>> ExecuteStoreQueryAsync<TElement>(String commandText, String entitySetName, ExecutionOptions executionOption, Object[] parameters)
  • Task<ObjectResult<TElement>> ExecuteStoreQueryAsync<TElement>(String commandText, String entitySetName, ExecutionOptions executionOption, CancellationToken cancellationToken, Object[] parameters)
  • Task<Int32> SaveChangesAsync()
  • Task<Int32> SaveChangesAsync(CancellationToken cancellationToken)
  • Task<Int32> SaveChangesAsync(SaveOptions options)
  • Task<Int32> SaveChangesAsync(SaveOptions options, CancellationToken cancellationToken)

Should we add ExecuteFunctionAsync? It depends on what we do with functions in DbContext, if we don't end up supporting Function Imports on DbContext then we should add ExecuteFunctionAsync. Added a note to http://entityframework.codeplex.com/workitem/818 to ensure we don't miss this if we cut Function Imports on DbContext from EF6.

[Action Item] We will be adding RefreshAsync to support ReloadAsync on DbEntityEntry.

System.Data.Entity.Core.Objects.ObjectQuery

  • Task<ObjectResult> ExecuteAsync(MergeOption mergeOption)
  • Task<ObjectResult> ExecuteAsync(MergeOption mergeOption, CancellationToken cancellationToken)

System.Data.Entity.Core.Objects.ObjectQuery<T>

  • Task<ObjectResult<T>> ExecuteAsync(MergeOption mergeOption)
  • Task<ObjectResult<T>> ExecuteAsync(MergeOption mergeOption, CancellationToken cancellationToken)

System.Data.Entity.Core.EntityClient.EntityCommand

  • Task<EntityDataReader> ExecuteReaderAsync()
  • Task<EntityDataReader> ExecuteReaderAsync(CancellationToken cancellationToken)
  • Task<EntityDataReader> ExecuteReaderAsync(CommandBehavior behavior)
  • Task<EntityDataReader> ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
  • Task<Int32> ExecuteNonQueryAsync(CancellationToken cancellationToken)

System.Data.Entity.Core.EntityClient.EntityConnection

  • Task OpenAsync(CancellationToken cancellationToken)

System.Data.Entity.Core.EntityClient.EntityDataReader

  • Task<Boolean> NextResultAsync(CancellationToken cancellationToken)
  • Task<Boolean> ReadAsync(CancellationToken cancellationToken)

System.Data.Entity.Core.Objects.DataClasses.IRelatedEnd

  • Task LoadAsync(CancellationToken cancellationToken)
  • Task LoadAsync(MergeOption mergeOption, CancellationToken cancellationToken)

System.Data.Entity.Core.Objects.DataClasses.RelatedEnd

  • Task LoadAsync(CancellationToken cancellationToken)
  • Task LoadAsync(MergeOption mergeOption, CancellationToken cancellationToken)

System.Data.Entity.Core.Objects.DataClasses.EntityCollection<TEntity>

  • Task LoadAsync(MergeOption mergeOption, CancellationToken cancellationToken)

System.Data.Entity.Core.Objects.DataClasses.EntityReference<TEntity>

  • Task LoadAsync(MergeOption mergeOption, CancellationToken cancellationToken)

System.Data.Entity.Core.Objects.DataClasses.IRelatedEndExtensions

  • Task LoadAsync(IRelatedEnd relatedEnd)
  • Task LoadAsync(IRelatedEnd relatedEnd, MergeOption mergeOption)

[Action Item] We will remove IRelatedEndExtensions. We don't use them internally and we don't really expect folks to interact with related ends very often.

System.Data.Entity.Spatial.DbSpatialDataReader

  • Task<DbGeography> GetGeographyAsync(Int32 ordinal)
  • Task<DbGeography> GetGeographyAsync(Int32 ordinal, CancellationToken cancellationToken)
  • Task<DbGeometry> GetGeometryAsync(Int32 ordinal)
  • Task<DbGeometry> GetGeometryAsync(Int32 ordinal, CancellationToken cancellationToken)

[Action Item] Remove the non-CancellationToken overloads as we don't use them internally and we don't expect folks to really interact with DbSpatialDataReader.

Exception Messages

IQueryable_Not_Async

Existing Message: The source IQueryable doesn't implement IDbAsyncEnumerable{0}.

[Action Item] Update message to:

The source IQueryable doesn't implement IDbAsyncEnumerable{0}. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.

[Action Item] Create guidance for scenarios where this can occur and update FWLink. In particular this can occur in tests.

IQueryable_Provider_Not_Async

Existing Message: The provider for the source IQueryable doesn't implement IDbAsyncQueryProvider.

[Action Item]Update message to:

The provider for the source IQueryable doesn't implement IDbAsyncQueryProvider. Only providers that implement IDbAsyncQueryProvider can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.

ConcurrentMethodInvocation

Existing Message: A concurrent method invocation has been detected. Ensure that any asynchronous methods invoked on this context have finished executing before calling any other method on the context. Also don't use the same context instance across different threads.

[Action Item] Update message to:

A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe.

Last edited Mar 19, 2013 at 3:17 AM by divega, version 7