I have the following method:
public static T ExecuteScalar<T>(
string query,
SqlConnection connection,
params SqlParameter[] parameters) where T : new()
{
// Create SqlCommand
SqlCommand command = CreateCommand(query, connection, parameters);
// Execute command using ExecuteScalar
object result = command.ExecuteScalar();
// Return value as expected type
if (result == null || result is DBNull) return default(T);
return (T)result;
}
I want to have the MIN_ACTIVE_ROWVERSION of the database as an ulong. The strange thing is.. the First method call below generates an error but the second method call works fine.
Method call 1 generates an error:
ulong minActiveRowversion =
SqlUtils.ExecuteScalar<ulong>(
"SELECT CAST(MIN_ACTIVE_ROWVERSION() AS BIGINT)"
, _connectionString);
Error:
System.InvalidCastException: Specified cast is not valid.
Method call 2 works fine:
ulong minActiveRowversion =
(ulong)SqlUtils.ExecuteScalar<long>(
"SELECT CAST(MIN_ACTIVE_ROWVERSION() AS BIGINT)"
, _connectionString);
I don't understand how that is possible because the result of the command.ExecuteScalar() method is this:
object result | 1955612
result.GetType() | {Name = "Int64" FullName = "System.Int64"}
Can someone tell me why the first scenario is not possible and the second scenario works?
Can someone tell me how I can solve it so I can use scenario 1.
Why
You can only unbox a value type to it's original type. In your case, the cast first needs to go to long from object and then to ulong.
See this question for more detail:
Why can't I unbox an int as a decimal?
It also links a blog post by Eric Lippert.
How
One way, as you know, is to cast to the original type before casting to T - unless, of course, the original type is T.
As mentioned in the comments, another way is to use conversion routines (Convert.ToUInt64) and not explicit casting.
This could potentially be achieved using a Func<object, T>:
public static T ExecuteScalar<T>(
Func<object, T> conversionFunctor,
string query,
SqlConnection connection,
params SqlParameter[] parameters) where T : new()
{
// Create SqlCommand
SqlCommand command = CreateCommand(query, connection, parameters);
// Execute command using ExecuteScalar
object result = command.ExecuteScalar();
// Return value as expected type
if (result == null || result is DBNull)
return default(T);
return conversionFunctor(result);
}
Making your call:
ulong minActiveRowversion =
SqlUtils.ExecuteScalar<ulong>(
Convert.ToUInt64,
"SELECT CAST(MIN_ACTIVE_ROWVERSION() AS BIGINT)"
, _connectionString);
Adam's answer correctly identifies the problem; here is a solution: you can use LINQ to unbox any type, as long as it can be cast to T with a built-in or a custom conversion.
static T UnboxUnchecked<T>(object obj) {
var pe = Expression.Parameter(typeof(object));
return Expression.Lambda<Func<object,T>>(
Expression.Convert(
Expression.Convert(pe, obj.GetType())
, typeof (T)
)
, pe
).Compile()(obj);
}
This method produces a LINQ expression that first unboxes the object to its actual type, and then applies the conversion. Replace the last line of your method
return (T)result;
with
return UnboxUnchecked<T>(result);
to make it work.
Here is a link to an article that explains how to make conversions of this kind more efficient by caching the compiled lambdas.
Related
I need to based on string type - for example 'UserModel'
execute method
Task<IEnumerable<T>> QueryAsync<T>(string sqlStatment, DynamicParameters parameters, CommandType commandType = CommandType.StoredProcedure, int timeout = 90, string connectionId = "Default");
so I have
string TypeName = "UserModel";
Type type = Type.GetType("XXX.Shared.CoreClasses."+ TypeName+", XX.Shared")!;
if(type is null) throw new ArgumentException(string.Format("type {0} not found", TypeName));
IList l = (IList)Activator
.CreateInstance(typeof(List<>)
.MakeGenericType(type))!;
System.Reflection.MethodInfo method = _sql.GetType().GetMethods().Where(c => c.Name == ("QueryAsync")
&& c.GetParameters()[1].ParameterType == typeof(DynamicParameters)).First().MakeGenericMethod(new Type[] { type });
object[] args = { SPname,d, CommandType.StoredProcedure,timeout };//not relevant
so now how to fill this l list with this method ?
like
l= await method.Invoke(this, args)!;
it yeals at me about casting / object canot be awaited ?
how to do this properly ?
is something like this slow ? or nowdays it does not matter until it will have to execute like xxxx times/sec ?
thanks and regards !
The QueryAsync<T> method returns a Task<IEnumerable<T>> instance.
But the result of calling this method through reflection via method.Invoke(this, args) is type-cast as object, and since the type for the generic type parameter is given as a type name string, it is impossible here to cast directly to Task<IEnumerable<TypeIdentifier>> and await it, because the TypeIdentifier has to be known and specified in the source code at compile-time.
object task = method.Invoke(this, args)!;
Although, from the question it looks like the QueryAsync method is an instance of the type of the variable _sql. Therefore, possibly the correct way to invoke this method is perhaps:
object task = method.Invoke(_sql, args)!;
But how can we await the task then and get the result? Another small static helper method will solve this issue. We are calling it through reflection again, thus avoiding the impossible step of casting the object-typed QueryAsync<T> result as some Task<IEnumerable<TypeIdentifier>> in our source code.
private static async Task<IEnumerable> AwaitQueryAsyncResult<T>(Task<IEnumerable<T>> task)
=> await task;
Note the return type. It's a task returning IEnumerable (which works because IEnumerable<T> inherits IEnumerable). In some sense we basically "converted" a Task<IEnumerable<TypeIdentifier>> we are unable to specify in the source code to a Task<IEnumerable> - a concrete type that can be specified in the source code. No more generic type parameter anymore we don't know about at compile-time!
From here on, it's pretty much straightforward. We will call our little generic helper method AwaitQueryAsyncResult<T> through reflection in similar fashion as has been done with the QueryAsync<T> method:
...
object task = method.Invoke(this, args)!;
var miAwaitQueryAsyncResult = typeof(TheTypeWhereAwaitQueryAsyncResultIsDeclared)
.GetMethod(nameof(AwaitQueryAsyncResult), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)
.MakeGenericMethod(type);
var resultAsEnumerable = await (Task<IEnumerable>) miAwaitQueryAsyncResult.Invoke(null, new[] { task } );
With QueryAsync<T>'s result now available as usefully typed resultAsEnumerable variable, it should be not too difficult to iterate/loop over it and add its elements to the list in the IList-typed variable l. I will leave the implementation of this little loop as a coffee-time exercise to the reader ;-)
Why does C# set these equal?
typeof(int).GetType() == typeof(int?).GetType()
The problem occurs when writing expression trees where I cast the
List<int?> ids = JsonConvert.DeserializeObject<List<int?>>(filter.Value?.ToString());
var filterField = filter.PropertyName;
var method = ids.GetType().GetMethod("Contains");
return Expression.Call(Expression.Constant(ids), method, member);
generates this error
System.ArgumentException: Expression of type 'System.Int32' cannot be used for parameter of type 'System.Nullable1[System.Int32]' of method 'Boolean Contains(System.Nullable1[System.Int32])
Is there a way to check the type before sending to the expression tree?
I tried checking the types of int and int? and both return true for the following check:
bool isIntNull = type == typeof(int?).GetType();
Why does C# set these equal?
Because they ARE equal.
typeof(int) generates a RuntimeType instance by the compiler
typeof(int?) generates a different RuntimeType instance by the compiler
calling GetType() on any RuntimeType instance returns the type System.RuntimeType
I think you want
typeof(int) == typeof(int?)
and
bool isIntNull = type.Equals(typeof(int?));
Proof:
Console.WriteLine(typeof(int));
Console.WriteLine(typeof(int?));
Console.WriteLine(typeof(int).GetType());
Console.WriteLine(typeof(int?).GetType());
output:
System.Int32
System.Nullable`1[System.Int32]
System.RuntimeType
System.RuntimeType
The typeof(X) operator always returns a Type object representing the type X. The GetType() method returns the runtime type of the object it is called on. So if you have the expression typeof(X).GetType() the first part of the expression will always return a Type instance, and the second part of that expression will always return a Type object representing the type Type, no matter what X is. You want to compare typeof(int) to typeof(int?), which are different.
I think, whats wrong with your expression tree is that the member variable is an Expression of type int instead of int?.
The code you posted didn't show where it is coming from, but I think the following would help you:
return Expression.Call(Expression.Constant(ids), method, Expression.Convert(member, typeof(int?)));
After searching for answers and trying everything here, found this.
bool isIntNull = member.Type.IsGenericType && member.Type.GetGenericTypeDefinition() == typeof(Nullable<>);
I have the same problem extracting data of an unknown runtime datatype to a known datatype - I solved the problem this way.
public bool CompareDataType<T>(Type runtimedatatype)
{
Type KT = typeof(T);
return runtimedatatype.Equals(KT) || runtimedatatype.Equals(Nullable.GetUnderlyingType(KT));
}
int? output = null;
object RunTimeData = (object)((int)0);
if (CompareDataType<int?>(RunTimeData.GetType()))
output = (int?)RunTimeData;
Alternatively you can create an extension of Object (which is what I went with in the end)
public static class ObjectTypeIsEqual
{
public static bool CompareDataType<T>(this object input)
{
Type ObjectType = input.GetType();
Type CompareType = typeof(T);
return ObjectType.Equals(CompareType) || ObjectType.Equals(Nullable.GetUnderlyingType(CompareType));
}
}
int? output = null;
object RunTimeData = (object)((int)0);
if (RunTimeData.CompareDataType<int?>())
output = (int?)RunTimeData;
Compile Error
'System.Data.SqlClient.SqlConnection' has no applicable method named 'Query' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.
Now, I know how to work around the problem, but I'm trying to get a better understanding of the error itself. I have class that I'm building to leverage Dapper. In the end I'm going to provide some more custom functionality to make our type of data access a lot more streamlined. In particular building in tracing and stuff. However, right now it's as simple as this:
public class Connection : IDisposable
{
private SqlConnection _connection;
public Connection()
{
var connectionString = Convert.ToString(ConfigurationManager.ConnectionStrings["ConnectionString"]);
_connection = new SqlConnection(connectionString);
_connection.Open();
}
public void Dispose()
{
_connection.Close();
_connection.Dispose();
}
public IEnumerable<dynamic> Query(string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
{
// this one works fine, without compile error, so I understand how to
// workaround the error
return Dapper.SqlMapper.Query(_connection, sql, param, transaction, buffered, commandTimeout, commandType);
}
public IEnumerable<T> Query<T>(string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
{
// this one is failing with the error
return (IEnumerable<T>)_connection.Query(sql, param, transaction, buffered, commandTimeout, commandType);
}
}
but interestingly enough, if I were to simply issue a statement like this:
_connection.Query("SELECT * FROM SomeTable");
it compiles just fine.
So, can somebody please help me understand why leveraging the same overload inside of those other methods is failing with that error?
So, can somebody please help me understand why leveraging the same overload inside of those other methods is failing with that error?
Precisely because you're using a dynamic value (param) as one of the arguments. That means it will use dynamic dispatch... but dynamic dispatch isn't supported for extension methods.
The solution is simple though: just call the static method directly:
return SqlMapper.Query(_connection, sql, param, transaction,
buffered, commandTimeout, commandType);
(That's assuming you really need param to be of type dynamic, of course... as noted in comments, you may well be fine to just change it to object.)
Another solution to the same issue is to apply type casting to the dynamic value.
I encountered the same compile error with:
Url.Asset( "path/" + article.logo );
Which was resolved by doing:
Url.Asset( "path/" + (string) article.logo );
Note: the dynamic value is well-known to be a string, in this case; a fact reinforced by the string concatenation that is present.
Suppose i have this sql statement and I have executed a sql command to get a datareader:
"select 1 union select 2"
//.....
var rdr = cmd.ExecuteReader();
and now i want to read the value in the first column of the first row:
var myInt = (int)rdr.GetValue(0); //great this works
var myLong = (long)rdr.GetValue(0); //throws cast exception, even though you can cast int to long
So it appears the type you cast to in C# needs to match exactly the SQL type. I.E. If the sql type is bigint, you can only cast to long. If the sql type is int, you can only cast to int. No mix and match...
I just want to get something that works regardless of the type of integer c# asks for and sql returns, as long as you could theoretically cast one to the other. So if SQL Server gives me a floating point type, and I'm asking for an int, I want the truncated int you get from doing that cast.
My goal is to make this work with generics, so I can have this function work when the generic parameter doesn't exactly match the datatype in sql server:
List<T> GetFirstColumn<T>(string sql) where T : struct
{
//get connection, execute reader
// loop:
// lst.Add( (T) rdr.GetValue(0));
}
I'd like this to work for both statments:
var sql1 = "Select 1"; //sql int
var sql2 = "Select cast(1 as bigint)"; //sql equivalent of a long
var lst1 = GetFirstColumn<int>(sql1);
var lst2 = GetFirstColumn<int>(sql2);
Does anyone have a relatively painless way of doing this?
Like Fredrik says, the value from SqlDataReader is boxed. You can convert a boxed value to an int with Convert.ToInt32, like:
int i = Convert.ToInt32(read[0]);
This will try to convert even if SQL Server returns a bigint or a decimal.
System.Convert will take care of the conversion.
T GetValue<T>(SqlDataReader rdr)
{
var dbVal = rdr.GetValue(0);
var csVal = (T)System.Convert.ChangeType(dbVal, typeof(T));
}
Caveat: if T == Nullable<S>, you need to do some extra work with reflection to get the underlying type and call ChangeType with typeof(S) as the type parameter. Apparently, MS didn't update the ChangeType function with .NET 2.0 and the introduction of nullables. And if it's a nullable, and dbVal is DBNull, you can just return null.
object dbValue = 5;
//this throws
Convert.ChangeType(dbValue, typeof(int?));
//this works
if(dbValue == DBNull.Value || dbValue == null)
{
if(typeof(int?).IsNullable) //or is a class, like string
{return null;}
dbValue = null;
}
var type = GetUnderlyingType<int?>(); //== typeof(int)
Convert.ChangeType(dbValue, type);
I think your problem is that GetValue returns an object. This means that in the case of an int, you will get an int boxed in an object. Then you cannot directly cast it to a long but must first unpack it as an int:
var myLong = (long)(int)rdr.GetValue(0);
This will be quite tricky using generics, I would say. Well, you could make generic methods with two type arguments; one specifying what type the field is, and one specifying the type you want. But I don't really see the need; SqlDataReader already has methods for the various data types, such as GetInt32, GetInt64 and so on, so the generic method would not really give any added value in that case.
I have a lambda expression which accepts, a int? (nullable integer),
which returns value if value exists or DBNull.Value otherwise.
Func<int?, object> getId = id => id.HasValue ? id.Value : (object)DBNull.Value;
The goal here is that, I want to make that expression slightly a bit more generic so that I can pass any nullable types like, DateTime?
So here is a non-functional code I was starting off with, but not sure where to specify nullable's type.
int? imageId;
DateTime? actionDate;
Func<Nullable<T>, object> getValue =
id => id.HasValue ? id.Value : (object) DBNull.Value;
SaveImage(getValue(imageId), getValue(actionDate));
Is it possible to specify generic type or should I create a named function to do so?
Since the purpose of the question is to use a lambda expression, here is a solution. It takes a different route by using weak typing instead of the proposed strong typing, but accomplishes the same thing nonetheless.
// A lambda solution
Func<object, object> fnGetValue =
v =>
ReferenceEquals(v, null)
? DBNull.Value
: v;
// Sample usage
int? one = 1;
int? two = null;
object o1 = fnGetValue(one); // gets 1
object o2 = fnGetValue(two); // gets DBNull
Edit: This loose typing works because the data type of the lambda argument v is of the struct itself and is not the Nullable type wrapper. Apparently the Nullable value that the caller uses has been resolved or 'unwrapped' by the time it hits the lambda argument and the lambda argument reveals a struct value or null; the Nullable wrapper is nowhere to be seen at this point (or as far as I can find). This behaviour can be proved by putting a debug breakpoint in the lambda at v and inspecting its value.
The good side effect of this behaviour is the lambda works equally well for both Nullable and non-Nullable types -- it's not restricted.
Instead of using generics, you can just make an extension method on Object to do the conversion.
Here's a sample program. The ToDbObject extension does the conversion:
using System;
static class Program
{
static object ToDbObject(this object value)
{
return value ?? DBNull.Value;
}
static void Main(string[] args)
{
int? imageId = 3;
DateTime? actionDate = null;
Console.WriteLine("ImageId {0}: [{1}] - {2}", imageId, imageId.ToDbObject(), imageId.ToDbObject().GetType());
Console.WriteLine("actionDate {0}: [{1}] - {2}", actionDate, actionDate.ToDbObject(), actionDate.ToDbObject().GetType());
Console.ReadKey();
}
}
The above prints:
ImageId 3: [3] - System.Int32
actionDate : [] - System.DBNull
It's correctly handling both cases.
I think you can do it by creating a delegate factory method where you can specify the generic type parameter:
public static Func<Nullable<T>, object> CreateGetValueFunc<T>() where T : struct
{
return id => id.HasValue ? id.Value : (object)DBNull.Value;
}
And you can use it in your example like this:
SaveImage(
CreateGetValueFunc<int>()(imageId),
CreateGetValueFunc<DateTime>()(actionDate));