diff --git a/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj b/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj
index 02ff2bfc..0e2bf425 100644
--- a/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj
+++ b/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj
@@ -31,9 +31,9 @@
- True
+
true
diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq/EFDynamicQueryableExtensions.cs b/src/Microsoft.EntityFrameworkCore.DynamicLinq/EFDynamicQueryableExtensions.cs
index afd46754..51ee6fee 100644
--- a/src/Microsoft.EntityFrameworkCore.DynamicLinq/EFDynamicQueryableExtensions.cs
+++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq/EFDynamicQueryableExtensions.cs
@@ -693,6 +693,93 @@ public static Task LastOrDefaultAsync([NotNull] this IQueryable source,
}
#endregion LastOrDefault
+ #region LongCount
+ private static readonly MethodInfo _longCount = GetMethod(nameof(Queryable.LongCount));
+
+ ///
+ /// Asynchronously returns the number of elements in a sequence.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// An that contains the elements to be counted.
+ ///
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ ///
+ /// A task that represents the asynchronous operation.
+ /// The task result contains the number of elements in the input sequence.
+ ///
+ [PublicAPI]
+ public static Task LongCountAsync([NotNull] this IQueryable source, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ Check.NotNull(source, nameof(source));
+ Check.NotNull(cancellationToken, nameof(cancellationToken));
+
+ return ExecuteAsync(_longCount, source, cancellationToken);
+ }
+
+ private static readonly MethodInfo _longCountPredicate = GetMethod(nameof(Queryable.LongCount), 1);
+
+ ///
+ /// Asynchronously returns the number of elements in a sequence that satisfy a condition.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// An that contains the elements to be counted.
+ ///
+ /// A function to test each element for a condition.
+ /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.
+ ///
+ /// A task that represents the asynchronous operation.
+ /// The task result contains the number of elements in the sequence that satisfy the condition in the predicate
+ /// function.
+ ///
+ [PublicAPI]
+ public static Task LongCountAsync([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args)
+ {
+ return LongCountAsync(source, default(CancellationToken), predicate, args);
+ }
+
+ ///
+ /// Asynchronously returns the number of elements in a sequence that satisfy a condition.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// An that contains the elements to be counted.
+ ///
+ /// A function to test each element for a condition.
+ /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ ///
+ /// A task that represents the asynchronous operation.
+ /// The task result contains the number of elements in the sequence that satisfy the condition in the predicate
+ /// function.
+ ///
+ [PublicAPI]
+ public static Task LongCountAsync([NotNull] this IQueryable source, CancellationToken cancellationToken, [NotNull] string predicate, [CanBeNull] params object[] args)
+ {
+ Check.NotNull(source, nameof(source));
+ Check.NotNull(predicate, nameof(predicate));
+ Check.NotNull(cancellationToken, nameof(cancellationToken));
+
+ LambdaExpression lambda = DynamicExpressionParser.ParseLambda(false, source.ElementType, null, predicate, args);
+
+ return ExecuteAsync(_longCountPredicate, source, Expression.Quote(lambda), cancellationToken);
+ }
+ #endregion LongCount
+
#region SingleOrDefaultAsync
private static readonly MethodInfo _singleOrDefault = GetMethod(nameof(Queryable.SingleOrDefault));
diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq/Microsoft.EntityFrameworkCore.DynamicLinq.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq/Microsoft.EntityFrameworkCore.DynamicLinq.csproj
index eb35df4e..533074e0 100644
--- a/src/Microsoft.EntityFrameworkCore.DynamicLinq/Microsoft.EntityFrameworkCore.DynamicLinq.csproj
+++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq/Microsoft.EntityFrameworkCore.DynamicLinq.csproj
@@ -35,9 +35,9 @@
- True
+
true
diff --git a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs
index 2da1c69f..85be5ae9 100644
--- a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs
+++ b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs
@@ -1120,6 +1120,79 @@ public static dynamic LastOrDefault([NotNull] this IQueryable source, [NotNull]
}
#endregion LastOrDefault
+ #region LongCount
+ private static readonly MethodInfo _longCount = GetMethod(nameof(Queryable.LongCount));
+
+ ///
+ /// Returns the number of elements in a sequence.
+ ///
+ /// The that contains the elements to be counted.
+ ///
+ ///
+ /// IQueryable queryable = employees.AsQueryable();
+ /// var result = queryable.LongCount();
+ ///
+ ///
+ /// The number of elements in the input sequence.
+ public static long LongCount([NotNull] this IQueryable source)
+ {
+ Check.NotNull(source, nameof(source));
+
+ return Execute(_longCount, source);
+ }
+
+ private static readonly MethodInfo _longCountPredicate = GetMethod(nameof(Queryable.LongCount), 1);
+
+ ///
+ /// Returns the number of elements in a sequence.
+ ///
+ /// The that contains the elements to be counted.
+ /// The .
+ /// A function to test each element for a condition.
+ /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.
+ ///
+ ///
+ /// IQueryable queryable = employees.AsQueryable();
+ /// var result1 = queryable.LongCount("Income > 50");
+ /// var result2 = queryable.LongCount("Income > @0", 50);
+ /// var result3 = queryable.Select("Roles.LongCount()");
+ ///
+ ///
+ /// The number of elements in the specified sequence that satisfies a condition.
+ [PublicAPI]
+ public static long LongCount([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
+ {
+ Check.NotNull(source, nameof(source));
+ Check.NotNull(config, nameof(config));
+ Check.NotEmpty(predicate, nameof(predicate));
+
+ bool createParameterCtor = SupportsLinqToObjects(config, source);
+ LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args);
+
+ return Execute(_longCountPredicate, source, lambda);
+ }
+
+ ///
+ public static long LongCount([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args)
+ {
+ return LongCount(source, ParsingConfig.Default, predicate, args);
+ }
+
+ ///
+ /// Returns the number of elements in a sequence.
+ ///
+ /// The that contains the elements to be counted.
+ /// A cached Lambda Expression.
+ /// The number of elements in the specified sequence that satisfies a condition.
+ public static long LongCount([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
+ {
+ Check.NotNull(source, nameof(source));
+ Check.NotNull(lambda, nameof(lambda));
+
+ return Execute(_longCountPredicate, source, lambda);
+ }
+ #endregion LongCount
+
#region OfType
private static readonly MethodInfo _ofType = GetGenericMethod(nameof(Queryable.OfType));
diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/IEnumerableSignatures.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/IEnumerableSignatures.cs
index c561694a..3fd1ebb2 100644
--- a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/IEnumerableSignatures.cs
+++ b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/IEnumerableSignatures.cs
@@ -32,6 +32,8 @@ internal interface IEnumerableSignatures
void Last(bool predicate);
void LastOrDefault();
void LastOrDefault(bool predicate);
+ void LongCount();
+ void LongCount(bool predicate);
void Max(object selector);
void Min(object selector);
void OfType(string type);
diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/IQueryableSignatures.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/IQueryableSignatures.cs
index 2e188ae4..3574bed0 100644
--- a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/IQueryableSignatures.cs
+++ b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/IQueryableSignatures.cs
@@ -31,6 +31,8 @@ internal interface IQueryableSignatures
void Last(bool predicate);
void LastOrDefault();
void LastOrDefault(bool predicate);
+ void LongCount();
+ void LongCount(bool predicate);
void Max(object selector);
void Min(object selector);
void OfType(string type);
diff --git a/src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj b/src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj
index 6399ff70..024e56c1 100644
--- a/src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj
+++ b/src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj
@@ -28,9 +28,9 @@
- True
+
true
diff --git a/test/System.Linq.Dynamic.Core.Tests/EntitiesTests.LongCount.cs b/test/System.Linq.Dynamic.Core.Tests/EntitiesTests.LongCount.cs
new file mode 100644
index 00000000..834db30a
--- /dev/null
+++ b/test/System.Linq.Dynamic.Core.Tests/EntitiesTests.LongCount.cs
@@ -0,0 +1,28 @@
+using System.Linq.Dynamic.Core.Tests.Helpers.Entities;
+using Xunit;
+
+namespace System.Linq.Dynamic.Core.Tests
+{
+ public partial class EntitiesTests
+ {
+ [Fact]
+ public void Entities_LongCount_Predicate()
+ {
+ const string search = "a";
+
+ //Arrange
+ var blog1 = new Blog { Name = "blog a", BlogId = 1000, Created = DateTime.Now };
+ var blog2 = new Blog { Name = "blog b", BlogId = 3000, Created = DateTime.Now };
+ _context.Blogs.Add(blog1);
+ _context.Blogs.Add(blog2);
+ _context.SaveChanges();
+
+ //Act
+ long expected = _context.Blogs.LongCount(b => b.Name.Contains(search));
+ long result = _context.Blogs.LongCount("Name.Contains(@0)", search);
+
+ //Assert
+ Assert.Equal(expected, result);
+ }
+ }
+}
diff --git a/test/System.Linq.Dynamic.Core.Tests/EntitiesTests.LongCountAsync.cs b/test/System.Linq.Dynamic.Core.Tests/EntitiesTests.LongCountAsync.cs
new file mode 100644
index 00000000..6b825bad
--- /dev/null
+++ b/test/System.Linq.Dynamic.Core.Tests/EntitiesTests.LongCountAsync.cs
@@ -0,0 +1,44 @@
+#if EFCORE
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.DynamicLinq;
+#else
+using System.Data.Entity;
+using EntityFramework.DynamicLinq;
+#endif
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+using System.Linq.Dynamic.Core.Tests.Helpers.Entities;
+using Xunit;
+
+namespace System.Linq.Dynamic.Core.Tests
+{
+ public partial class EntitiesTests
+ {
+ [Fact]
+ public async Task Entities_LongCountAsync_Predicate_Args()
+ {
+ const string search = "a";
+
+ //Arrange
+ var blog1 = new Blog { Name = "blog a", BlogId = 1000, Created = DateTime.Now };
+ var blog2 = new Blog { Name = "blog b", BlogId = 3000, Created = DateTime.Now };
+ _context.Blogs.Add(blog1);
+ _context.Blogs.Add(blog2);
+ _context.SaveChanges();
+
+ Expression> predicate = b => b.Name.Contains(search);
+
+#if EFCORE
+ var expected = await EntityFrameworkQueryableExtensions.LongCountAsync(_context.Blogs, predicate);
+#else
+ var expected = await QueryableExtensions.LongCountAsync(_context.Blogs, predicate);
+#endif
+
+ //Act
+ long result = await (_context.Blogs as IQueryable).LongCountAsync("Name.Contains(@0)", search);
+
+ //Assert
+ Assert.Equal(expected, result);
+ }
+ }
+}
diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Count.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Count.cs
index 3a8c99af..f9e4c320 100644
--- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Count.cs
+++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Count.cs
@@ -53,5 +53,35 @@ public void Count_Predicate_WithArgs()
//Assert
Assert.Equal(expected, result);
}
+
+ [Fact]
+ public void Count_Dynamic_Select()
+ {
+ // Arrange
+ IQueryable queryable = User.GenerateSampleModels(1).AsQueryable();
+
+ // Act
+ var expected = queryable.Select(x => x.Roles.Count()).ToArray();
+ var result = queryable.Select("Roles.Count()").ToDynamicArray();
+
+ // Assert
+ Assert.Equal(expected, result);
+ }
+
+ [Fact]
+ public void Count_Dynamic_Where()
+ {
+ const string search = "e";
+
+ // Arrange
+ var testList = User.GenerateSampleModels(10);
+ var queryable = testList.AsQueryable();
+
+ // Act
+ var expected = queryable.Where(u => u.Roles.Count(r => r.Name.Contains(search)) > 0).ToArray();
+ var result = queryable.Where("Roles.Count(Name.Contains(@0)) > 0", search).ToArray();
+
+ Assert.Equal(expected, result);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.LongCount.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.LongCount.cs
new file mode 100644
index 00000000..22697c13
--- /dev/null
+++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.LongCount.cs
@@ -0,0 +1,87 @@
+using System.Linq.Dynamic.Core.Tests.Helpers.Models;
+using Xunit;
+
+namespace System.Linq.Dynamic.Core.Tests
+{
+ public partial class QueryableTests
+ {
+ [Fact]
+ public void LongCount()
+ {
+ //Arrange
+ IQueryable testListFull = User.GenerateSampleModels(100).AsQueryable();
+ IQueryable testListOne = User.GenerateSampleModels(1).AsQueryable();
+ IQueryable testListNone = User.GenerateSampleModels(0).AsQueryable();
+
+ //Act
+ var resultFull = testListFull.LongCount();
+ var resultOne = testListOne.LongCount();
+ var resultNone = testListNone.LongCount();
+
+ //Assert
+ Assert.Equal(100, resultFull);
+ Assert.Equal(1, resultOne);
+ Assert.Equal(0, resultNone);
+ }
+
+ [Fact]
+ public void LongCount_Predicate()
+ {
+ //Arrange
+ var queryable = User.GenerateSampleModels(100).AsQueryable();
+
+ //Act
+ long expected = queryable.LongCount(u => u.Income > 50);
+ long result = queryable.LongCount("Income > 50");
+
+ //Assert
+ Assert.Equal(expected, result);
+ }
+
+ [Fact]
+ public void LongCount_Predicate_WithArgs()
+ {
+ const int value = 50;
+
+ //Arrange
+ var queryable = User.GenerateSampleModels(100).AsQueryable();
+
+ //Act
+ long expected = queryable.LongCount(u => u.Income > value);
+ long result = queryable.LongCount("Income > @0", value);
+
+ //Assert
+ Assert.Equal(expected, result);
+ }
+
+ [Fact]
+ public void LongCount_Dynamic_Select()
+ {
+ // Arrange
+ IQueryable queryable = User.GenerateSampleModels(1).AsQueryable();
+
+ // Act
+ var expected = queryable.Select(x => x.Roles.LongCount()).ToArray();
+ var result = queryable.Select("Roles.LongCount()").ToDynamicArray();
+
+ // Assert
+ Assert.Equal(expected, result);
+ }
+
+ [Fact]
+ public void LongCount_Dynamic_Where()
+ {
+ const string search = "e";
+
+ // Arrange
+ var testList = User.GenerateSampleModels(10);
+ var queryable = testList.AsQueryable();
+
+ // Act
+ var expected = queryable.Where(u => u.Roles.LongCount(r => r.Name.Contains(search)) > 0).ToArray();
+ var result = queryable.Where("Roles.LongCount(Name.Contains(@0)) > 0", search).ToArray();
+
+ Assert.Equal(expected, result);
+ }
+ }
+}