public virtual ObjectResult<Nullable<byte>> GetPersonalPicture3(Nullable<System.Guid> contactId)
{
var contactIdParameter = contactId.HasValue ?
new ObjectParameter("ContactId", contactId) :
new ObjectParameter("ContactId", typeof(System.Guid));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Nullable<byte>>("GetPersonalPicture3", contactIdParameter);
}
in the bottom Code, I Faced this error "The specified cast from a materialized 'System.Byte[]' type to a nullable 'System.Byte' type is not valid."
byte x = DBPSO.GetPersonalPicture3(ProfileID).FirstOrDefault() ?? 0000;
in addition, I've tested this Code too
var x = DBPSO.GetPersonalPicture3(ProfileID).Select(B => B.Value).ToArray();
string binaryPic = System.Text.Encoding.Unicode.GetString(x);
The picture on the db is probably a varbinary so an array of byte and not a single byte.
Try this:
public virtual ObjectResult<byte[]> GetPersonalPicture3(Nullable<System.Guid> contactId)
{
var contactIdParameter = contactId.HasValue ?
new ObjectParameter("ContactId", contactId) :
new ObjectParameter("ContactId", typeof(System.Guid));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<byte[]>("GetPersonalPicture3", contactIdParameter);
}
Related
I'm not sure if there is a way to support this, but I'm having trouble getting Dapper to map string parameter values to the Postgresql citext data type as it seems to be using the text type.
In particular, I'm trying to call a function that takes in citext parameters - the error I get back is:
var c = ConnectionManager<T>.Open();
string sql = #"select * from ""dbo"".""MyFunction""(#schemaName, #tableName);";
var param = new
{
schemaName = schema,
tableName = table
};
string insecureSalt = c.QueryMultiple(sql, param).Read<string>().FirstOrDefault();
ConnectionManager<T>.Close(c);
Error: Npgsql.PostgresException: 42883: function dbo.MyFunction(text, text) does not exist.
The signature that would match is function dbo.MyFunction(citext, citext) so clearly it can't find it using the default mapping.
According to Npgsql - http://www.npgsql.org/doc/types.html I need to be able to specify NpgsqlDbType.Citext as the type but I can't find a way to do this using Dapper.
Solved thanks to answer from Shay, complete solution here:
var c = ConnectionManager<T>.Open();
string sql = #"select * from ""dbo"".""MyFunction""(#schemaName, #tableName);";
var param = new
{
schemaName = new CitextParameter(schema),
tableName = new CitextParameter(table)
};
string insecureSalt = c.QueryMultiple(sql, param).Read<string>().FirstOrDefault();
ConnectionManager<T>.Close(c);
public class CitextParameter : SqlMapper.ICustomQueryParameter
{
readonly string _value;
public CitextParameter(string value)
{
_value = value;
}
public void AddParameter(IDbCommand command, string name)
{
command.Parameters.Add(new NpgsqlParameter
{
ParameterName = name,
NpgsqlDbType = NpgsqlDbType.Citext,
Value = _value
});
}
}
You probably need to create create a CitextParameter which extends ICustomQueryParameter. This API allows you to pass an arbitrary DbParameter instance to Dapper - in this case it would be an instance of NpgsqlParameter with its NpgsqlDbType set to Citext.
Something like this should work:
class CitextParameter : SqlMapper.ICustomQueryParameter
{
readonly string _value;
public CitextParameter(string value)
{
_value = value;
}
public void AddParameter(IDbCommand command, string name)
{
command.Parameters.Add(new NpgsqlParameter
{
ParameterName = name,
NpgsqlDbType = NpgsqlDbType.Citext,
Value = _value
});
}
}
When you write the SQL query, you can cast the parameter value like cast(#param as citext).
in my case below worked correctly. (usr is a class object)
string sql = "select * from users where user_name = cast(#user_name as citext) and password = #password;";
IEnumerable<users> u = cnn.Query<users>(sql, usr);
In your case, you can change the query like below and see if that works
string sql = #"select * from ""dbo"".""MyFunction""(cast(#schemaName as citext), cast(#tableName as citext));";
In EF, Order By allows a column name to be used to eg OrderBy("Description")
I need to be able to do some thing similar with GroupBy
Other posts have solutions when the column type is known
var groupByExpressionGN2 = GetGroupByExpressionGuidNull<DebtWaiver>("PersonUID");
...
// in the query
.GroupBy(groupByExpression2)
// the Expression function
private static Expression<Func<TEntity,Guid?>> GetGroupByExpressionGuidNull<TEntity>(string property)
{
var item = Expression.Parameter(typeof(TEntity), "gb");
var itemProperty = Expression.PropertyOrField(item, property);
var lambda = Expression.Lambda<Func<TEntity, Guid?>>(itemProperty, item);
return lambda;
}
But my users may select 1 of any columns by which to group by
So how can I make the function above return an expression for group by
I have tried this:
public static Expression<Func<T, object>> GetMember<T>(string memberName)// where T : EntityObject
{
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
System.Reflection.PropertyInfo pi = typeof(T).GetProperty(memberName);
return (Expression<Func<T, object>>)Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(pe, pi), typeof(object)), pe);
}
but it produces : p =>Convert(p.PersonUID)
instead of:p =>p.PersonUID
Regards
GregJF
After a bit more testing (and a good night's sleep) I got the second method to work (Thanks to JA Rreyes )
My issue was that I was using this:
var groupByExpressionGN2 = GetGroupByExpressionGuidNull<DebtWaiver>("PersonUID");
...
// in the query
.GroupBy(groupByExpression2)
I should have being doing this:
var groupByExpression2 = GetMember<DebtWaiver>("PersonUID");
...
// in the query
.GroupBy(groupByExpression2.Compile())
You can use the second method in my original post( GetMember ), but I use this method('cos I like it!): Thanks: Taher Rahgooy
public static Expression<Func<T, object>> GetPropertySelector<T>(string propertyName)
{
var arg = Expression.Parameter(typeof(T), "gb");
var property = Expression.Property(arg, propertyName);
var conv = Expression.Convert(property, typeof(object));
var exp = Expression.Lambda<Func<T, object>>(conv, new ParameterExpression[] { arg });
return exp;
}
Regards
GregJF
Im working with a custom plugin for CRM online 2015 and every time I try to access the activityparty from the field "Email.To" I get
"base {System.SystemException} = {"Unable to cast object of type 'Microsoft.Xrm.Sdk.Entity' to type ...ActivityParty'."}"
Here is how my code looks like:
public class PreCreate : Plugin
{
public PreCreate()
: base(typeof(PreCreate))
{
base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(20, "Create", "email", new Action<LocalPluginContext>(ExecutePreEntityCreate)));
}
public void ExecutePreEntityCreate(LocalPluginContext localContext)
{
var target = (Entity)localContext.PluginExecutionContext.InputParameters["Target"];
using (var context = new XrmServiceContext(localContext.OrganizationService))
{
var email = target.ToEntity<Email>(); //The entity has the right values
var activityPartyList=email.To // here I see the exception
//If I use the following code:
var activityParty = email.GetAttributeValue<EntityCollection>("to");
//I get an empty ActivityParty(empty Id)
}
}
}
Do I have to do some initialization for activityparty types?
There is no issue with the code, the field Email.To will return a EntityCollection and to obtain that you need to use:
var entityCollection = email.GetAttributeValue<EntityCollection>("to");
This will give you a collection of entities that need to be converted to ActivityParty(entityCollection.Entities).
To convert the Entities you need to:
foreach (var entityItem in entityCollection.Entities)
{
var ap = entityItem.ToEntity<ActivityParty>();
//Here you will get the LogicalName in this case Lead
// the Id and the name
var leadId = ap.PartyId.Id;
//To get the Lead
var lead=context.LeadSet.FirstOrDefault(l => l.Id == leadId);
}
I want to implement expression tree for integers as in below query:
Select * From TableName Where PKID In (1,2,3,4,5)
The relevant extracted code:
protected Expression<Func<T, bool>> GetExpression<T>(string propertyName, string propertyValue, string propertyType)
{
var parameter = Expression.Parameter(typeof(T), "type");
switch (propertyType)
{
case "string":
case "string?":
var stringProperty = Expression.Property(parameter, propertyName);
var stringValue = Expression.Constant(propertyValue.Trim(), typeof(string));
MethodInfo stringMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var stringContainsMethod = Expression.Call(stringProperty, stringMethod, stringValue);
return Expression.Lambda<Func<T, bool>>(stringContainsMethod, parameter);
case "int?":
var intProperty = Expression.Property(parameter, propertyName);
var intValues = Expression.Constant(propertyValue.Trim(), typeof(string));
MethodInfo intMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var intContainsMethod = Expression.Call(intProperty, intMethod, intValues); // this line gives error
return Expression.Lambda<Func<T, bool>>(intContainsMethod, parameter);
}
}
// Calling above function for string works. Products is a table in Database and Entity framework generated the class based on database first.
var filterLambda = GetExpression<Products>("ProductName", "chicken", "string?"); // No error here, works great
// Calling above function for int gives error
var filterLambda = GetExpression<Products>("ProductId", "1,2,3,4,5", "int?"); // Error here
I get error:
Method 'Boolean Contains(System.String)' declared on type 'System.String' cannot be called with instance of type 'System.Int32'
Of course it is pretty much clear that the column ProductId is integer and the value is string. Integer doesnt have contains so I thought I should use strings contains method. Please can any one tell me how do I solve this?
I'm creating a dynamic expression builder and trying to implement the 'like' function. Before writing my own I've searched for any existing function and found one close to my need. After several experiments I couldn't bring it to run for types other than string.
When I pass a parameter of type int then I get this error:
Method 'System.String ToString()' declared on type 'System.String' cannot be called with instance of type 'System.Int32'
My code looks like this:
private static MethodCallExpression GetLowerCasePropertyAccess(MemberExpression propertyAccess)
{
//return Expression.Call(Expression.Call(propertyAccess, "ToString", new Type[0]), typeof(string).GetMethod("ToLower", new Type[0]));
return Expression.Call(Expression.Call(propertyAccess, typeof(string).GetMethod("ToString", System.Type.EmptyTypes)), typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
}
private static readonly MethodInfo ContainsMethod = typeof(String).GetMethod("Contains", new Type[] { typeof(String) });
public static Expression<Func<T, bool>> Create<T>(string propertyName, ComparisonOperators comparisonOperator, dynamic comparedValue1, dynamic comparedValue2 = null)
{
ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "x");
MemberExpression memberExpression = Expression.MakeMemberAccess(parameterExpression, typeof(T).GetProperty(propertyName));
ConstantExpression constantExpression = Expression.Constant(comparedValue1, comparedValue1.GetType());
Expression expressionBody = null;
switch (comparisonOperator)
{
...
case ComparisonOperators.Contains:
//var indexOf = Expression.Call(memberExpression, "IndexOf", null, Expression.Constant(comparedValue1, typeof(string)), Expression.Constant(StringComparison.InvariantCultureIgnoreCase));
//expressionBody = Expression.GreaterThanOrEqual(indexOf, Expression.Constant(0));
expressionBody = Expression.Call(GetLowerCasePropertyAccess(memberExpression), ContainsMethod, Expression.Constant(comparedValue1.ToLower()));
break;
}
return Expression.Lambda<Func<T, bool>>(expressionBody, new ParameterExpression[] { parameterExpression });
}
I'm not sure I fully understand what you're doing, but I think your error is caused by this line:
return Expression.Call(Expression.Call(propertyAccess, typeof(string).GetMethod("ToString", System.Type.EmptyTypes)), typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
Which will always try and call the ToString method for a string type, so if you try and use an Int32 property, you're then trying to call String.ToString(), since the implementation of ToString() will be different for different types and the two implementations will not necessarily be compatible, you'll get the exception you're seeing:
Method 'System.String ToString()' declared on type 'System.String' cannot be called with instance of type 'System.Int32'
From what it looks like you're doing, I think this may be what you're after:
return Expression.Call(Expression.Call(propertyAccess, propertyAccess.Type.GetMethod("ToString", System.Type.EmptyTypes)), typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
Which will use the correct implementation of ToString (with type obtained from propertyAccess.Type).
Linq to entities doesn't support .ToString method. For converting numeric values to string you need to use SqlFunctions.StringConvert method. I've fixed your code and now you can do like on string and numeric columns:
private static Expression GetConvertToStringExpression(Expression e)
{
// if property string - no cast needed
// else - use SqlFunction.StringConvert(double?) or SqlFunction.StringConvert(decimal?);
Expression strExpression = null;
if (e.Type == typeof(string))
strExpression = e;
var systemType = Nullable.GetUnderlyingType(e.Type) ?? e.Type;
if (systemType == typeof(int)
|| systemType == typeof(long)
|| systemType == typeof(double)
|| systemType == typeof(short)
|| systemType == typeof(byte)) // continue
{
// cast int to double
var doubleExpr = Expression.Convert(e, typeof (double?));
strExpression = Expression.Call(StringConvertMethodDouble, doubleExpr);
}
if (systemType == typeof (decimal))
{
// call decimal version of StringConvert method
// cast to nullable decimal
var decimalExpr = Expression.Convert(e, typeof (decimal?));
strExpression = Expression.Call(StringConvertMethodDecimal, decimalExpr);
}
return strExpression;
}
private static MethodCallExpression GetLowerCasePropertyAccess(Expression propertyAccess)
{
var stringExpression = GetConvertToStringExpression(propertyAccess);
if (stringExpression == null)
throw new Exception(string.Format("Not supported property type {0}", propertyAccess.Type));
return Expression.Call(stringExpression,
typeof (string).GetMethod("ToLower", Type.EmptyTypes));
}
private static readonly MethodInfo StringConvertMethodDouble = typeof (SqlFunctions).GetMethod("StringConvert",
new Type[] {typeof (double?)});
private static readonly MethodInfo StringConvertMethodDecimal = typeof(SqlFunctions).GetMethod("StringConvert",
new Type[] { typeof(decimal?) });
I have just made something like that:
public Expression<Func<T,bool>> BuildContainsExpression<T>(MemberExpression memberExp, object comparedValue)
{
var parameter = Expression.Parameter(memberExp.Member.DeclaringType, "x");
var method = typeof(string).GetMethod("Contains", types: new[] { typeof(string) });
var comparison = Expression.Equal(
Expression.Call(
method: method,
instance: memberExp,
arguments: Expression.Constant(comparedValue)),
Expression.Constant(true)
);
return Expression.Lambda<Func<T, bool>>(comparison, parameter);
}
And it builds an expression like below:
x.Language.Contains("tr")
(with my dynamic parameters)