We have a working solution that uses the specification pattern to access CosmosDb using plain text SQL statements.
We are attempting to use the latest version of Ardalis.Specification (5.1.0) to do the same, but using LINQ to provide type safety in our sql.
For a collection foo
we have a specification:
using System.Linq;
using Ardalis.Specification;
using Example.Sample.Core.Entities;
namespace Example.Sample.Core.Specifications
{
public class FooFromIdSpecification : Specification<Foo>
{
public FooFromIdSpecification(string id)
{
Query.Where(x => x.Id == id);
}
}
}
Where we are having problems is in the base generic repository ... getting the code to generate the sql from specification:
public async IAsyncEnumerable<T> GetItemsAsyncEnumerable(ISpecification<T> specification)
{
# This is the line that is not working
var foo = (IQueryable<T>)specification.Evaluate(_container.GetItemLinqQueryable<T>());
using var iterator = foo.ToFeedIterator<T>();
while (iterator.HasMoreResults)
{
var response = await iterator.ReadNextAsync();
foreach (var item in response)
{
yield return item;
}
}
}
Hit a wall getting the evaluator to work. Likely missing something obvious.
The problem
The code above when called does not hit any try-catch blocks, but foo
is null.
We 'got something working' ... not elegant but does the job.
Gotcha - there is no way my colleagues and I discovered of using SelectMany using main implementation, which is needed when getting arrays from separate collections e.g. in SQL world:
This is what worked:
Implementing that interface to get the SelectMany functionality down the stack:
Should probably have changed the
InMemorySpecificationEvaluator.Default
singleton to our own ... but current implementation works and getting on with things.This then all gets stitched together in repository using bespoke evaluator-like thing:
and use as so in your generic base repository:
With a specification something like: