SingleOrNewIdentified(o => o.prop, value), setting o.prop when new - c#

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.

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;
}

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.

Related

Combine property selector expression tree and value to create a predicate for EF filtering - create filter from lambda selector and value

Given a simple class with arbitrary properties (for discussion lets say Id, Name, and Description)
and given an instance of that class, I want to find matching entries in the database by specifying the property to match
I'm trying to do something in this respect similar to the AddOrUpdate method of EF, but I need the entity returned to me for further processing.
var match = new SomeClass{Name="Whatever"};
var found = Context.SomeClass.Find(x=>x.Name, match);
public static T Find<T>(this DbSet<T> set, Expression<Func<T, object>> matchOn, T matchAgainst) where T : class {
var func = matchOn.Compile();
var valueToFind = func(matchAgainst);
var combinedExpression = //matchon + "=" + valueToFind;
var found = set.FirstOrDefault(combinedExpression);
return found;
}
That gives me the value of the property in the passed in object, but I need to now combine that value with the passed in expression and pass it to the db set.
IE, the code I'm effectively trying to run is set.FirstOrDefault(x=>x.Name==valueToFind) How do I take the matchon expression (which contains x=>x.Name) and combine that with the ==valueToFind to get the x=>x.Name==valueToFind from them?
How do I build the combined expression? (I realize the "string" code above is completely wrong, but I was trying to get across what I need the function to do, but I have no idea what that syntax would look like.)
For manually coded examples, it would be easy enough just to pass in a hardcoded lambda with the value set, but my use case involves running through a collection of objects and finding the match for each one, so the value will not be known until runtime, and the method must work against arbitrary types and various properties, so I can't hardcode the property name either.
If you have a property selector, and a value to compare to, you can get an expression tree like this:
public static Func<TEntity, bool> GetComparer<TEntity,TProperty>(
Expression<Func<TEntity,TProperty>> selector, TProperty value)
{
var propertyRef = selector.Body;
var parameter = selector.Parameters[0];
var constantRef = Expression.Constant(value);
var comparer
= Expression.Lambda<Func<TEntity, bool>>
(Expression.Equal(propertyRef, constantRef), parameter)
.Compile();
return comparer;
}
Sample usage:
var comparer = GetComparer<Person, string>(p => p.Name, "John");
var persons = Person.GetPersons();
var john = persons.FirstOrDefault(comparer);

Creating an IQueryable to Equal int32?

I am trying to create an query extension which would compare a nullable int sql column value with a value. But i am struggling already over 8 hours to find any working solution.
I have already found a lot of help on this side. But all the remarks did not helped me.
I have altered the code so many times, but nothing seems to work. I want to create something similar as WHERE ManagerID IN (10,20,30)
The main code
IQueryable<Users> query = _context.CreateObjectSet<Users>();
query = query.IsMember(a => a.ManagerID, new Int32?[] { 10,20,30 });
return query.ToList();
Currently while executing the query.ToList(); it returns me a
Unable to create a constant value of type 'System.Object'. Only primitive types or enumeration types are supported in this context.
public static IQueryable<T> IsMember<T>(this IQueryable<T> source, Expression<Func<T, Int32?>> stringProperty, params Int32?[] searchTerms)
{
if (searchTerms == null || !searchTerms.Any())
{
return source;
}
Expression orExpression = null;
foreach (var searchTerm in searchTerms)
{
var searchTermExpression = Expression.Constant(searchTerm, typeof(object)); // <<--- This cast would make it no longer a primitive type
var containsExpression = Expression.Call(stringProperty.Body, typeof(Int32?).GetMethod("Equals"), searchTermExpression);
orExpression = BuildOrExpression(orExpression, containsExpression);
}
var completeExpression = Expression.Lambda<Func<T, bool>>(orExpression, stringProperty.Parameters);
return source.Where(completeExpression);
}
private static Expression BuildOrExpression(Expression existingExpression, Expression expressionToAdd)
{
return existingExpression == null ? expressionToAdd : Expression.OrElse(existingExpression, expressionToAdd);
}
The line marked to give the constant another datatype, is indeed causing the issue, but if I dont make it of type object, the Expression will not work, as it could not match the Int32? datatype.
Can anybody help me?
thanks
=============================================
Additional info
It is indeed to had a a larger picture.
I just want to create something more dynamic which could be used on other projects also.
I would like to use some functions which will look appealing than all those multilines
query = query.Like(a => a.UserName, filter.UserName, true);
query = query.Equals(a => a.UserTown, filter.UserTown, true);
query = query.IsMember(a => a.Division, filter.Division); // is an array of possible divisions
it worked fine for Like and Equals which are string based. But want to have a similar product for (nullable) integers
I was inspired by the following post. Which created a search function (which i renamed for my project to Like)
link
I wanted to create others similar. the last boolean is to verify if nullable in the column is allowed or not.
The reason also to use an extension, is that i also have alot of filters in my filter page.
With this extension, i would easily check in the beginning of my Like and Equal function if a filter was given without checking if my filter has a value 20x.
public static IQueryable<T> Like<T>(this IQueryable<T> source, Expression<Func<T, string>> stringProperty, string searchTerm, bool isnullValueAllowed)
if (String.IsNullOrEmpty(searchTerm))
{
return query;
}
It's not clear why you want to create this extension as you could simply write something like:
query.Where(user => (new[]{10,20,30}).Contains(user.ManagerId)).ToList();
However, assuming the real use case is somewhat more complicated than the example you've given, could you not construct your expression as either a comparison against a constant Int32 or a comparison against null, depending on whether searchTerm.HasValue() was true?
You need to use the equality operator == rather than the Equals method here. It actually makes your expression code a tad simpler:
foreach (var searchTerm in searchTerms)
{
var comparison = Expression.Equals(stringProperty.Body,
Expression.Constant(searchTerm));
orExpression = BuildOrExpression(orExpression, comparison);
}
Of course, as is mentioned by others, you don't need to build up an expression representing an OR of each of these comparisons, you can simply use Conatains on the set in a lambda and the query provider will do all of this for you.

Conversion problem with Expression Trees

I have an expression tree function from a previous SO question. It basically allows the conversion of a data row into a specific class.
This code works fine, unless you're dealing with data types that can be bigger or smaller (eg. Int32/Int64).
The code throws an invalid cast exception when going from an Int64 to an Int32 when the value would fit in an Int32 (eg. numbers in the 3000).
Should I?
Attempt to fix this in the code? (If so, any pointers?)
Leave the code as it is.
private Func<SqlDataReader, T> getExpressionDelegate<T>()
{
// hang on to row[string] property
var indexerProperty = typeof(SqlDataReader).GetProperty("Item", new[] { typeof(string) });
// list of statements in our dynamic method
var statements = new List<Expression>();
// store instance for setting of properties
ParameterExpression instanceParameter = Expression.Variable(typeof(T));
ParameterExpression sqlDataReaderParameter = Expression.Parameter(typeof(SqlDataReader));
// create and assign new T to variable: var instance = new T();
BinaryExpression createInstance = Expression.Assign(instanceParameter, Expression.New(typeof(T)));
statements.Add(createInstance);
foreach (var property in typeof(T).GetProperties())
{
// instance.MyProperty
MemberExpression getProperty = Expression.Property(instanceParameter, property);
// row[property] -- NOTE: this assumes column names are the same as PropertyInfo names on T
IndexExpression readValue = Expression.MakeIndex(sqlDataReaderParameter, indexerProperty, new[] { Expression.Constant(property.Name) });
// instance.MyProperty = row[property]
BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(readValue, property.PropertyType));
statements.Add(assignProperty);
}
var returnStatement = instanceParameter;
statements.Add(returnStatement);
var body = Expression.Block(instanceParameter.Type, new[] { instanceParameter }, statements.ToArray());
var lambda = Expression.Lambda<Func<SqlDataReader, T>>(body, sqlDataReaderParameter);
// cache me!
return lambda.Compile();
}
Update:
I have now given up and decided it is not worth it. From the comments below, I got as far as:
if (readValue.Type != property.PropertyType)
{
BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(Expression.Call(property.PropertyType, "Parse", null, new Expression[] { Expression.ConvertChecked(readValue, typeof(string)) }), property.PropertyType));
statements.Add(assignProperty);
}
else
{
// instance.MyProperty = row[property]
BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(readValue, property.PropertyType));
statements.Add(assignProperty);
}
I don't think I was too far off, feel free to finish it and post the answer if you figure it out :)
You could try to fix it by "convert checked" before assigning i.e. using Expression.ConvertChecked on the value instead of Expression.Convert .
Couldn't try it right now but this should take care of the case you describe...
EDIT - as per comment this could be a boxing issue:
In this case you could try using Expression.TypeAs or Expression.Unbox for the conversion or use Expression.Call for calling a method to do the conversion... an example for using Call can be found at http://msdn.microsoft.com/en-us/library/bb349020.aspx
What you're trying to build is actually much more complicated if you want to support 100% of the primitives in .NET and SQL.
If you don't care about some of the edge cases (nullable types, enums, byte arrays, etc), two tips to get you 90% there:
Don't use the indexer on IDataRecord, it returns an object and the boxing/unboxing will kill performance. Instead, notice that IDataRecord has Get[typeName] methods on it. These exist for all .NET primitive types (note: it's GetFloat, not GetSingle, huge annoyance).
You can use IDataRecord.GetFieldType to figure out which Get method you need to call for a given column. Once you have that, you can use Expression.Convert to coerce the DB column type to the target property's type (if they're different). This will fail for some of the edge cases I listed above, for those you need custom logic.

Reading a property value with a lambda expression

I'm writing a file generic block for my application and started with using Lambda expressions for managing my rule sets for block generation to avoid the pitfalls of magic strings, configuration hell etc.
Inside my mapping class I have lines similar to:
Map(x => x.Name).Length(20).PadLeft(true).PaddingChar("#");
This works fine and isn't where my question dwells, where I setup saving my information about the expression is in the Map method:
public override IPropertyMap Map(Expression<Func<T, object>> expression)
{
var propertyMap = new FixedLengthPropertyMap
{
//Length = 20,
//PaddingCharacter = " ",
PadLeft = false,
PropertyInfo = ReflectionHelper.GetProperty(expression)
};
_properties.Add(propertyMap);
return propertyMap;
}
_properties is just a List<IPropertyMap> that stores my info where my question from what is the best way to have a real object's data be read from the properties currently I came up with something similar to this:
var map = new AgentMap();
var agent = new Agent {Name = "Bob"};
string output = map.Write(agent);
public override string Write<T>(T agent)
{
var initial = _properties[0];
return initial.PropertyInfo.GetValue(agent, null) as string;
}
Is there a better way than using the GetValue method since earlier on I'm using an expression tree?
I don't see why you really need to use expression trees at all. Just make the Map method take a Func<T, object> and store that:
public override IPropertyMap Map(Func<T, string> fetcher)
{
var propertyMap = new FixedLengthPropertyMap
{
//Length = 20,
//PaddingCharacter = " ",
PadLeft = false,
Delegate = fetcher // Delegate is of type Delegate
};
_properties.Add(propertyMap);
return propertyMap;
}
Then:
public override string Write<T>(T agent)
{
var initial = _properties[0];
Func<T, string> fetcher = (Func<T, string>) initial.Delegate;
return fetcher(agent);
}
Is there any reason you particularly wanted to know the property and use an expression tree?
In part, it depends on what your scenario is. The "simple" answer is to just compile the expression and invoke it, but that has a potential performance impact if you are doing it in a tight loop (passing a delegate would be a lot quicker).
I'm not sure whether if would apply in this particular case (because of the agent), but to avoid doing too much expression compilation, you can look for simple scenarios and read the value directly from the expression tree; a little bit of PropertyInfo/FieldInfo is going to be quicker than compiling it...
For more, look at TryEvaluate here, and how it is used with Compile as a backup strategy (although you have the advantage of a known delegate type).

What's the best way to define & access selected properties in C#?

From my recent question, I try to centralize the domain model by including some silly logic in domain interface. However, I found some problem that need to include or exclude some properties from validating.
Basically, I can use expression tree like the following code. Nevertheless, I do not like it because I need to define local variable ("u") each time when I create lambda expression. Do you have any source code that is shorter than me? Moreover, I need some method to quickly access selected properties.
public void IncludeProperties<T>(params Expression<Func<IUser,object>>[] selectedProperties)
{
// some logic to store parameter
}
IncludeProperties<IUser>
(
u => u.ID,
u => u.LogOnName,
u => u.HashedPassword
);
Thanks,
Lambdas are great for many scenarios - but if you don't want them, perhaps simply don't use them? I hate to say it, but simple strings are tried and tested, especially for scenarios like data binding. If you want fast access, you could look at HyperDescriptor, or there are ways of compiling a delegate to the property accessors, or you can build an Expression from the string and compile it (including a cast to object if you want a known signature, rather than calling the (much slower) DynamicInvoke).
Of course, in most cases even crude reflection is fast enough, and isn't the bottleneck.
I suggest starting with the simplest code, and check it is actually too slow before worrying about it being fast. If it isn't too slow, don't change it. Any of the above options would work otherwise.
Another thought; if you are using Expression, you could do something like:
public void IncludeProperties<T>(
Expression<Func<T,object>> selectedProperties)
{
// some logic to store parameter
}
IncludeProperties<IUser>( u => new { u.ID, u.LogOnName, u.HashedPassword });
and then take the expression apart? A bit tidier, at least... here's some sample code showing the deconstruction:
public static void IncludeProperties<T>(
Expression<Func<T, object>> selectedProperties)
{
NewExpression ne = selectedProperties.Body as NewExpression;
if (ne == null) throw new InvalidOperationException(
"Object constructor expected");
foreach (Expression arg in ne.Arguments)
{
MemberExpression me = arg as MemberExpression;
if (me == null || me.Expression != selectedProperties.Parameters[0])
throw new InvalidOperationException(
"Object constructor argument should be a direct member");
Console.WriteLine("Accessing: " + me.Member.Name);
}
}
static void Main()
{
IncludeProperties<IUser>(u => new { u.ID, u.LogOnName, u.HashedPassword });
}
Once you know the MemberInfos (me.Member in the above), building your own lambdas for individual access should be trivial. For example (including a cast to object to get a single signature):
var param = Expression.Parameter(typeof(T), "x");
var memberAccess = Expression.MakeMemberAccess(param, me.Member);
var body = Expression.Convert(memberAccess, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(body, param);
var func = lambda.Compile();
Here's the shortest expression I can come up with:
public static void IncludeProperties(Expression<Action<IUser>> selectedProperties)
{
// some logic to store parameter
}
public static void S(params object[] props)
{
// dummy method to get to the params syntax
}
[Test]
public void ParamsTest()
{
IncludeProperties(u => S(
u.Id,
u.Name
));
}

Categories