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

Can multi-condition query add WhereIf extension similar to abp #143

Closed
Uchiha-Peng opened this issue Aug 28, 2021 · 5 comments · Fixed by #192
Closed

Can multi-condition query add WhereIf extension similar to abp #143

Uchiha-Peng opened this issue Aug 28, 2021 · 5 comments · Fixed by #192
Milestone

Comments

@Uchiha-Peng
Copy link

When there are multiple query conditions at the same time and do not know whether each query condition has a value, we must first determine whether the condition is empty, and then determine whether to add it to the filter condition, using Where is more troublesome, whether Provide a WhereIf extension similar to Abp, that is very convenient, this is just a request for optimization, thank you.

db.Employee
.WhereIf<Employee>(!string.IsNullOrEmpty(query.key), n => n.Name == query.key || n.Description.Contains(query.key)).ToList();
@fiseni
Copy link
Collaborator

fiseni commented Sep 4, 2021

Hey @Uchiha-Peng

I can see how this can be helpful. I would actually not introduce a new term for that, instead just overload the Where extension.
Example usage:

public class CustomerSpec : Specification<Customer>
{
    // Instead of having this
    public CustomerSpec(CustomerFilter filter)
    {
        if (!string.IsNullOrEmpty(filter.Name))
            Query.Where(x => x.Name == filter.Name);

        if (!string.IsNullOrEmpty(filter.Email))
            Query.Where(x => x.Email == filter.Email);

        if (!string.IsNullOrEmpty(filter.Address))
            Query.Search(x => x.Address, "%" + filter.Address + "%");
    }

    // Users can do this
    public CustomerSpec(CustomerFilter filter)
    {
        Query
            .Where(x => x.Name == filter.Name, condition: !string.IsNullOrEmpty(filter.Name))
            .Where(x => x.Email == filter.Email, condition: !string.IsNullOrEmpty(filter.Email))
            .Search(x => x.Address, "%" + filter.Address + "%", condition: !string.IsNullOrEmpty(filter.Address));
    }
}

You can do it even now, you just need to add the following extension in your projects. We tried to make the infrastructure quite extensible (even though I'm still not happy with it).

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

// Keep the same namespace, so it can be discovered automatically
namespace Ardalis.Specification
{
    public static class MySpecificationBuilderExtensions
    {
        public static ISpecificationBuilder<T> Where<T>(
            this ISpecificationBuilder<T> specificationBuilder,
            Expression<Func<T, bool>> criteria,
            bool condition)
        {
            if (condition)
            {
                ((List<Expression<Func<T, bool>>>)specificationBuilder.Specification.WhereExpressions).Add(criteria);
            }

            return specificationBuilder;
        }
    }
}

@ardalis any thoughts? We need some more feedback from users if this is something they want, and perhaps include it OOTB. I see @MisinformedDNA disliked this one :)

@Uchiha-Peng
Copy link
Author

I later thought about it carefully, in fact, there is no need to expand, just use the ternary operator, which is what I do now

Query
                .Where(n => string.IsNullOrWhiteSpace(query.KeyWoard) ? true : (
                n.Name.Contains(query.KeyWoard) ||
                n.Phone.Contains(query.KeyWoard) ||
                n.Remark.Contains(query.KeyWoard) ||
                n.Address.Contains(query.KeyWoard))
                ).Where(n => (query.Gender.HasValue ? n.Gender == query.Gender.Value : true));

@fiseni
Copy link
Collaborator

fiseni commented Sep 5, 2021

You have to be careful with that. That logic is in the expression body and is not evaluated immediately as you think. So, that would work only if the given ORM can process it accordingly. EF Core can handle the above scenarios, but don't push the limits and keep the statements as simple as possible.

@takato1314
Copy link

Would be really nice if the overload method mentioned by @fiseni gets implemented in the future release. On one hand, if we need general query for an entity collection and then do some filter on it if some keyword exists then this would be very convenient. Otherwise if we need to query for some other specific criteria for indexing and caching we can always make a more specific Specification without any conditions.

@fiseni
Copy link
Collaborator

fiseni commented Dec 7, 2021

I like this feature. It can be useful if specs are used in combination with "filters". I'm reopening this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants