Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LINQ query with predicate #684

Open
j82w opened this issue Aug 14, 2019 · 0 comments
Open

LINQ query with predicate #684

j82w opened this issue Aug 14, 2019 · 0 comments
Labels
discussion-wanted Need a discussion on an area LINQ QUERY

Comments

@j82w
Copy link
Contributor

j82w commented Aug 14, 2019

Describe the bug
A user can do the following code. This is very bad because it is doing a synchronous read feed. IQueryable.Where does not support taking in a func. Only the IEnumerable.Where supports func. This will cause the SDK will read all the items from the container so it returns an IEnumerable. The IEnumerable.Where then can be ran over all the items on the client side. This very inefficient and consume a lot of RUs.

List<Family> families = new List<Family>();
            Func<Family, bool> v = new Func<Family, bool>(x => true);
            // SQL
            IEnumerable<Family> setIterator = container.GetItemLinqQueryable<Family>(true).Where(v).AsEnumerable<Family>();
                foreach (Family item in setIterator)
                {
                    families.Add(item);
                }
            
            Assert("Expected two families", families.ToList().Count == 2);

The user should pass in an expression rather than a function. The expression can be parsed into a SQL query. This means all the filtering is done on Cosmos DB and only the required items are returned. The code should also be run asynchronously to avoid performance issue once the application starts to scale.

Expression<Func<Family, bool>> func = (family) => family.id != "test5";
IEnumerable<Family> results = await QueryHelper(container, func);
...
public async Task<IEnumerable<Family>> QueryHelper(Container container, Expression<Func<Family, bool>> predicate)
        {
            IQueryable<Family> queryable = container.GetItemLinqQueryable<Family>().Where(predicate);

            FeedIterator<Family> feedIterator = queryable.ToFeedIterator();
            List<Family> familyResults = new List<Family>();
            while (feedIterator.HasMoreResults)
            {
                familyResults.AddRange(await feedIterator.ReadNextAsync());
            }

            return familyResults;

There are 2 solutions I see that can help prevent other users from hitting this.

  1. Add a request option that has to be enabled to support sync read feed.
  2. Implement a custom ICosmosQueryable that is almost identical to the current IQueryable. The big difference is we can have an explicit ExecuteAsync to actually run the query. This would also allow the ability to support CountAsync and other aggregates.
@j82w j82w added discussion-wanted Need a discussion on an area LINQ labels Aug 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion-wanted Need a discussion on an area LINQ QUERY
Projects
None yet
Development

No branches or pull requests

2 participants