Question

I'd like a C# SingleOrNewIdentified(o => o.prop, value) function, responsible for returning a new o with o.prop = value preset when Any(o.prop == value) is not found. Unfortunately my understanding of expressions and lambdas is poor.

I frequently find myself needing to uniquely set just the one identifier (e.g. emailAddress, oauthId, GUID, natural key) before using a new EF object in a write-many manner. This write-once assignment often makes me shuffle some blocks around in a less-than-clear way.

It seems likely that it can be done since I'd be fine with reflection. I wouldn't want to defeat type checking in consumers of this function in any way, though.

Warnings about this idea are also welcome.

Was it helpful?

Solution

public static T SingleOrNewIdentified<T, TProp>(this IQueryable<T> queryable, Expression<Func<T, TProp>> propExpr, TProp value) where T : class, new()
{
    var property = (PropertyInfo)((MemberExpression)propExpr.Body).Member;
    var paramExpr = Expression.Parameter(typeof(T));
    var eqExpr = Expression.Equal(Expression.Property(paramExpr, property), Expression.Constant(value));
    var predicate = Expression.Lambda<Func<T, bool>>(eqExpr, paramExpr);

    T maybe = queryable.SingleOrDefault(predicate);
    if (maybe != null) return maybe;

    T @default = new T();
    property.SetValue(@default, value);

    return @default;
}

OTHER TIPS

Not sure if this is what you want but it seems you can do it this way: if your collection is null, assign a default:

var foo = /*db.FooTable.*/SingleOrDefault(x => /*your where clause*/) ?? new Foo
                                              {
                                                  EmailMember = "me@foo.now"   
                                              }; 

It's not what I was looking for, but I thought I should note a related functionality for EF (update-or-create-by-indentity) for simplifying attaching at the end rather than beginning of your process, for entity keys only:

db.Attach(model);
db.SaveChanges();

It's been easy for me to forget that EF will do this work for you, but it maps especially well to UIs where create and update are very similar. You have to wait for SaveChanges() for a generated entity key of course.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top