diff --git a/Dapper.Contrib/SqlMapperExtensions.Expression.Async.cs b/Dapper.Contrib/SqlMapperExtensions.Expression.Async.cs
new file mode 100644
index 000000000..2109b6b5e
--- /dev/null
+++ b/Dapper.Contrib/SqlMapperExtensions.Expression.Async.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dapper.Contrib.Extensions
+{
+ public static partial class SqlMapperExtensions
+ {
+ ///
+ /// Returns a list of entities from table "Ts" based on predicate expression.
+ /// Id of T must be marked with [Key] attribute.
+ /// Entities created from interfaces are tracked/intercepted for changes and used by the Update() extension
+ /// for optimal performance.
+ /// Entities can be filtered using predicate expression
+ ///
+ /// Interface or type to create and populate
+ /// Open SqlConnection
+ /// Search terms
+ /// The transaction to run under, null (the default) if none
+ /// Number of seconds before command execution timeout
+ /// Entity of T
+ public static Task> GetAllAsync(this IDbConnection connection, Expression> predicate,
+ IDbTransaction transaction = null, int? commandTimeout = null) where T : class
+ {
+ var type = typeof(T);
+ var cacheType = typeof(List);
+
+ if (!GetQueries.TryGetValue(cacheType.TypeHandle, out string sql))
+ {
+ GetSingleKey(nameof(GetAll));
+ var name = GetTableName(type);
+
+ var where = CreateWhereClause(predicate);
+
+ sql = $"SELECT * FROM {name} {where}";
+ GetQueries[cacheType.TypeHandle] = sql;
+ }
+
+ return !type.IsInterface
+ ? connection.QueryAsync(sql, null, transaction, commandTimeout)
+ : GetAllAsyncImpl(connection, transaction, commandTimeout, sql, type);
+ }
+
+ ///
+ /// Delete n matching entities in the table related to the type T asynchronously using Task based.
+ ///
+ /// Type of entity
+ /// Open SqlConnection
+ /// Filter to apply for deletion
+ /// The transaction to run under, null (the default) if none
+ /// Number of seconds before command execution timeout
+ /// true if deleted, false if none found
+ public static async Task DeleteAllAsync(this IDbConnection connection, Expression> predicate,
+ IDbTransaction transaction = null, int? commandTimeout = null) where T : class
+ {
+ var type = typeof(T);
+ var where = CreateWhereClause(predicate);
+
+ var statement = $"DELETE FROM {GetTableName(type)} {where}";
+ var deleted = await connection.ExecuteAsync(statement, null, transaction, commandTimeout).ConfigureAwait(false);
+ return deleted > 0;
+ }
+
+ private static string CreateWhereClause(Expression> predicate)
+ {
+ if (predicate == null)
+ return "";
+
+ var p = new StringBuilder(predicate.Body.ToString());
+ var pName = predicate.Parameters.First();
+ p.Replace(pName.Name + ".", "");
+ p.Replace("==", "=");
+ p.Replace("AndAlso", "and");
+ p.Replace("OrElse", "or");
+ p.Replace("\"", "\'");
+ return $"WHERE {p}";
+ }
+ }
+}
diff --git a/tests/Dapper.Tests.Contrib/TestSuite.Expressions.Async.cs b/tests/Dapper.Tests.Contrib/TestSuite.Expressions.Async.cs
new file mode 100644
index 000000000..450f179e2
--- /dev/null
+++ b/tests/Dapper.Tests.Contrib/TestSuite.Expressions.Async.cs
@@ -0,0 +1,111 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Dapper.Contrib.Extensions;
+using Xunit;
+
+namespace Dapper.Tests.Contrib
+{
+ public abstract partial class TestSuite
+ {
+ [Fact]
+ public async Task GetAllAsyncWithOrExpression()
+ {
+ const int numberOfEntities = 10;
+
+ var users = new List(numberOfEntities);
+
+ for (var i = 0; i < numberOfEntities; i++)
+ users.Add(new User {Name = "User " + i, Age = i});
+
+ using (var connection = GetOpenConnection())
+ {
+ await connection.DeleteAllAsync().ConfigureAwait(false);
+
+ var total = await connection.InsertAsync(users).ConfigureAwait(false);
+ Assert.Equal(total, numberOfEntities);
+
+ users = (List) await connection.GetAllAsync(x => x.Age == 5 || x.Age == 6).ConfigureAwait(false);
+ Assert.Equal(2, users.Count);
+ Assert.NotNull(users.FirstOrDefault(x => x.Age == 5));
+ Assert.NotNull(users.FirstOrDefault(x => x.Age == 6));
+
+ var iusers = await connection.GetAllAsync(x => x.Age == 5 || x.Age == 6).ConfigureAwait(false);
+ Assert.Equal(2, iusers.Count());
+ Assert.NotNull(iusers.FirstOrDefault(x => x.Age == 5));
+ Assert.NotNull(iusers.FirstOrDefault(x => x.Age == 6));
+ }
+ }
+
+ [Fact]
+ public async Task GetAllAsyncWithAndExpression()
+ {
+ const int numberOfEntities = 10;
+
+ var users = new List(numberOfEntities);
+
+ for (var i = 0; i < numberOfEntities; i++)
+ users.Add(new User {Name = "User " + i, Age = i});
+
+ using (var connection = GetOpenConnection())
+ {
+ await connection.DeleteAllAsync().ConfigureAwait(false);
+
+ var total = await connection.InsertAsync(users).ConfigureAwait(false);
+ Assert.Equal(total, numberOfEntities);
+
+ users = (List) await connection.GetAllAsync(x => x.Age == 5 && x.Id == 6).ConfigureAwait(false);
+ Assert.Single(users);
+ Assert.NotNull(users.FirstOrDefault(x => x.Age == 5 && x.Id == 6));
+
+ var iusers = await connection.GetAllAsync(x => x.Age == 5 && x.Id == 6).ConfigureAwait(false);
+ Assert.Single(iusers);
+ Assert.NotNull(iusers.FirstOrDefault(x => x.Age == 5 && x.Id == 6));
+ }
+ }
+
+ [Fact]
+ public async Task GetAllAsyncWithStringExpression()
+ {
+ const int numberOfEntities = 10;
+
+ var users = new List(numberOfEntities);
+
+ for (var i = 0; i < numberOfEntities; i++)
+ users.Add(new User {Id = 100 + i, Name = "User " + i, Age = i});
+
+ using (var connection = GetOpenConnection())
+ {
+ await connection.DeleteAllAsync().ConfigureAwait(false);
+
+ var total = await connection.InsertAsync(users).ConfigureAwait(false);
+ Assert.Equal(total, numberOfEntities);
+
+ users = (List) await connection.GetAllAsync(x => x.Name == "User 5").ConfigureAwait(false);
+ Assert.Single(users);
+ Assert.NotNull(users.FirstOrDefault(x => x.Name == "User 5"));
+
+ var iusers = await connection.GetAllAsync(x => x.Name == "User 5").ConfigureAwait(false);
+ Assert.Single(iusers);
+ Assert.NotNull(iusers.FirstOrDefault(x => x.Name == "User 5"));
+ }
+ }
+
+ [Fact]
+ public async Task DeleteAllAsyncWithExpression()
+ {
+ using (var connection = GetOpenConnection())
+ {
+ await connection.DeleteAllAsync().ConfigureAwait(false);
+
+ var id1 = await connection.InsertAsync(new User {Name = "Alice", Age = 32}).ConfigureAwait(false);
+ var id2 = await connection.InsertAsync(new User {Name = "Bob", Age = 33}).ConfigureAwait(false);
+
+ await connection.DeleteAllAsync(x => x.Name == "Alice").ConfigureAwait(false);
+
+ Assert.Null(await connection.GetAsync(id1).ConfigureAwait(false));
+ Assert.NotNull(await connection.GetAsync(id2).ConfigureAwait(false));
+ }
+ }
+ }
+}