Meelfan Bmfp
Meelfan Bmfp

Reputation: 605

compressing code with C# generics

I have the following 2 methods that i thing could be compressed in one method using generics. What i have tried can not compile. Can someone let me know how this can be done? I need to check that 2 differents field of the table AgeLengths have at least one values. Str_table has one to many relationship with AgeLengths.

public static bool HasMeanWeight(int id)
{
    MyDataContext dc = new MyDataContext ();
    return  (from s in dc.Str_table 
             where s.SId == id 
             select s.AgeLengths
             .Where(a => a.MeanWeight != null ).Any() == true
            ).FirstOrDefault();
}

public static bool HasNumbersData(int id)
{
    MyDataContext dc = new MyDataContext ();
    return (from s in dc.Str_table 
            where s.sId == id 
            select s.AgeLengths
            .Where(a => a.Numbers  != null).Any() == true
           ).FirstOrDefault();
}

Thanks in advance B

Upvotes: 3

Views: 160

Answers (2)

Dennis
Dennis

Reputation: 37770

If you're using some DataContext, you're using IQueryable<T>, and you're very limited with stuff you can write in your expressions. So, you need to pass an expression to your method, not a predicate itself:

static bool HasData(int id, Expression<Func<AgeLength, bool>> predicate)
{
    using (MyDataContext dc = new MyDataContext())
    {
        return (from s in dc.Str_table
                where s.sId == id
                select s.AgeLengths
                .Any(predicate)
               ).FirstOrDefault();
    }
}

Besides:

  • there's Any overload, that accepts predicate expression;
  • context must be disposed (see using);
  • there's no need to write someBoolExpression == true; just write someBoolExpression.

Than you can call this method like this:

HasData(1, a => a.MeanWeight != null);
HasData(1, a => a => a.Numbers  != null);

Note, that the second argument is a lambda expression, not a method.
This is because of lazy nature of queries: you're providing a set of expressions, and the corresponding provider converts them into appropriate SQL.

Upvotes: 3

Adam Houldsworth
Adam Houldsworth

Reputation: 64487

Update: Apologies, I didn't realise this was linq to sql. Dennis's answer appears to be on the mark.

Try injecting a Func<T, TResult> to inject the differing code:

public static bool HasData(int id, Func<AgeLength, object> selector)
{
    MyDataContext dc = new MyDataContext ();
    return (from s in dc.Str_table 
            where s.sId == id 
            select s.AgeLengths
                .Where(a => selector(a) != null)
                .Any())
           .FirstOrDefault();
}

And call like so:

HasData(1, a => a.Numbers);
HasData(1, a => a.MeanWeight);

If the Numbers and MeanWeight properties are in the same inheritance hierarchy, then you can substitute object with something more useful, but in this instance object is fine as you are just testing for null.

Upvotes: 5

Related Questions