score:0

Accepted answer

I guess thinking more about it, it is somewhat of a stupid question. I was hoping to be able to use the cleaner query:

var query = from b in DataContext.B 
            select b;

And apply this to it:

x => x.A.Name == "Test"

Without having to have the duplicate this predicate that I use when starting the query on the A table:

x => x.Name == "Test"

So I suppose the solution is to "reverse" the query by starting on the A table, like so:

var query = from a in DataContext.A
            join b in B on a equals b.A
            select b;

query = query.Where(FilterPredicate());

I was thinking it may rewrite the queries inefficiently, but that doesn't seem to be the case.

score:3

You can do this by defining an interface over A and B.

public interface IHasName // contrived, I know
{
    string Name {get;}
}

LINQ-To-SQL classes are partial, so in your part of the partial class definition, you can add the interface like so:

public partial class A : IHasName {}
public partial class B : IHasName {}

As you see, no implementation should be needed since the Name property is implemented in the Linq-To-Sql generated part.

Now constrain your predicate to types implementing the IHasName interface, and you're all set:

private Expression<Func<T, bool>> FilterPredicate(string name) where T : IHasName
{
    return x => x.Name == name;
}

you should now even be able to define an extension method on IQueryable like so:

public static T GetByName<T>(this IQueryable<T> queryable, 
                             string name) where T : IHasName
{
    return queryable.Where(FilterPredicate(name)).SingleOrDefault();
}

Small caveat: of course, the property in the interface ('Name') must exactly match the property name in the implementing classes. Suppose you have a class C with property 'MyName'. You might be tempted to implement the IHasName interface like so:

public partial class C : IHasName
{
    public string Name {return MyName;} 
} 

This will of course not work, as the Linq-To-Sql expression parser will use 'Name' instead of the actual property 'MyName', so it won't be able to map this expression to valid SQL.


Related Articles