Home > Mobile >  How to refactor linq predicate into Func variable
How to refactor linq predicate into Func variable

Time:08-11

I have this code:

if (model.Id > 0)
{
  return _buyerRepository.Exists(x => (model.Id != x.Id) &&
      (x.IdentificationNumber == model.IdentificationNumber));
}

return _buyerRepository.Exists(x =>
    x.IdentificationNumber == model.IdentificationNumber);

How to extract (model.Id != x.Id) and to put in the linq query based on if model.Id>0 or it's a 0 ? I am thinking on ExpressionTrees and Func<T,bool>, but Im not sure how to put a condition.

CodePudding user response:

I would move from Exists to Any and do the following:

IEnumerable<T> query = (IEnumerable<T>)_buyerRepository;
if (model.Id > 0)
  query = query.Where(x => model.Id != x.Id);

return query.Any(x => x.IdentificationNumber == model.IdentificationNumber);

See an example here:

https://dotnetfiddle.net/EkoDym

public class Program
{
    public static void Main()
    {
        var foos = new List<Foo>()
        {
            new Foo() { Id = 1, IdentificationNumber = "1" },
            new Foo() { Id = 2, IdentificationNumber = "2" },
        };
        
        Console.WriteLine(HasAny(foos, 1, "1"));
        Console.WriteLine(HasAny(foos, 0, "1"));
        
        
        var foosv2 = new List<Foo>()
        {
            new Foo() { Id = 2, IdentificationNumber = "1" },
        };
        
        Console.WriteLine(HasAny(foosv2, 1, "1"));
        Console.WriteLine(HasAny(foosv2, 2, "1"));
    }
    
    static bool HasAny(List<Foo> foos, int id, string identificationNumber)
    {
        IEnumerable<Foo> query = (IEnumerable<Foo>)foos;
        if (id > 0)
            query = query.Where(x => id != x.Id);

        return query.Any(x => x.IdentificationNumber == identificationNumber);
    }
}

public class Foo
{
    public int Id { get; set; }
    public string IdentificationNumber { get; set; }
}

In case you may believe that the Where condition will be evaluated for all items before Any you don't have to worry about it that is the laziness of LINQ and Where will only be evaluated till Any finds a result.

You can see here a demo: https://dotnetfiddle.net/Wen09a

public class Program
{
    public static void Main()
    {
        var foos = new List<Foo>()
        {
            new Foo() { Id = 1, IdentificationNumber = "1" },
            new Foo() { Id = 2, IdentificationNumber = "2" },
            
            new Foo() { Id = 3, IdentificationNumber = "3" },
            new Foo() { Id = 4, IdentificationNumber = "4" },
            new Foo() { Id = 5, IdentificationNumber = "5" },
            new Foo() { Id = 6, IdentificationNumber = "6" },
        };
        
        Console.WriteLine(HasAny(foos, 1, "2"));
    }
    
    static bool HasAny(List<Foo> foos, int id, string identificationNumber)
    {
        IEnumerable<Foo> query = (IEnumerable<Foo>)foos;
        if (id > 0)
            query = query.Where(x => 
            {
                Console.WriteLine($"Compare Ids - {id} and {x.Id}");
                return id != x.Id;
            });

        return query.Any(x => x.IdentificationNumber == identificationNumber);
    }
}

public class Foo
{
    public int Id { get; set; }
    public string IdentificationNumber { get; set; }
}

Even though I have declared the Ids 3 to 6 which would all be unequal to the id 1 it will stop searching on the first positive value for Any.

  • Related