Strange predicate behavior

I haven’t tested this on other dialects, but just ran into some bizarre behavior that took me a while to track down.

I have a method like this:

public static T GetOrCreateLookupRecord<T>(this IServiceContext serviceContext, T record) where T: ILookup, new()
        {
            var lkp = serviceContext.Db.Single<T>(r => r.Name == record.Name);
            if (lkp != null) return lkp;

            if (record.Id == Guid.Empty) record.Id = Guid.NewGuid();
            serviceContext.Db.Insert(record);
            return record;
        }

When I look at the sql generated here: serviceContext.Db.Single<T>(r => r.Name == record.Name);, it looks like this (which obviously is wrong, or at least not what I expected).

SELECT "Id", "Name"
FROM "dis_lkp_pis"
WHERE ("Name" = "Name")
LIMIT 1

Doing the following works though:

var name = record.Name;
var lkp = serviceContext.Db.Single<T>(r => r.Name == name);

which generates the sql

SELECT "Id", "Name"
FROM "dis_lkp_offices"
WHERE ("Name" = @0)
LIMIT 1

Is this a bug? and if not, how do I rationalize it so I don’t run into this sort of expression evaluation issue in the future, because I wouldn’t have ever thought this could be an issue.

It’s kind of a bug in that when selecting against an interface in a generic method the expression tree is wrapped in a convert expression which trips the heuristics in determining whether it’s a constant expression whose value should be used instead of its column name.

I.e. both of these can be easily determined:

db.Single<Table>(r => r.Name == name);
db.Single<Table>(r => r.Name == record.Name);

But when you wrap it behind a generic method that codes against a different Type (i.e. its interface), it wraps the expression in a convert expression so that both sides of this binary expression look like they’re both referencing a column name of the Record Type, i.e:

public static T M<T>(T record) where T: ILookup
{
    db.Single<Table>(r => r.Name == record.Name);
}

I’ve managed to resolve this with finer-grained heuristics in this commit, just needed to visit deeper and unwrap the convert expressions that were added.

This fix is available from v5.6.1 that’s now available on MyGet.

1 Like

Thanks, I’ll test this out this week.