tmsmith / Dapper-Extensions

Dapper Extensions is a small library that complements Dapper by adding basic CRUD operations (Get, Insert, Update, Delete) for your POCOs. For more advanced querying scenarios, Dapper Extensions provides a predicate system. The goal of this library is to keep your POCOs pure by not requiring any attributes or base class inheritance.
1.79k stars 585 forks source link

Casting error in Get and GetAsync methods #262

Closed hfrances closed 3 years ago

hfrances commented 3 years ago

Hello, when I try to call to Get / GetAsync methods, I get an error.

Code examples:

Entities.MyItem rdo;

rdo = conn.Get<Entities.MyItem>(new { Id = pk });
rdo = await conn.GetAsync<Entities.MyItem>(new { Id = pk });

Error message: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot implicitly convert type 'object' to 'System.Collections.Generic.IEnumerable'. An explicit conversion exists (are you missing a cast?) Stack Trace: at CallSite.Target(Closure , CallSite , Object ) at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0) at DapperExtensions.DapperImplementor.InternalGet[T](IDbConnection connection, Object id, IDbTransaction transaction, Nullable1 commandTimeout, IList1 colsToSelect, IList1 includedProperties) at System.Dynamic.UpdateDelegates.UpdateAndExecute7[T0,T1,T2,T3,T4,T5,T6,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) at DapperExtensions.DapperImplementor.Get[T](IDbConnection connection, Object id, IDbTransaction transaction, Nullable1 commandTimeout, IList1 includedProperties) at System.Dynamic.UpdateDelegates.UpdateAndExecute5[T0,T1,T2,T3,T4,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4) at DapperExtensions.DapperExtensions.Get[T](IDbConnection connection, Object id, IDbTransaction transaction, Nullable1 commandTimeout)

Possible solution: DapperExtensionsFix DapperExtensionsFixAsync

I appreciate your support.

valfrid-ly commented 3 years ago

In your suggestion you are returning SYNC from an async method. Did you run the unit tests??

valfrid-ly commented 3 years ago

With the suggested change we have a problem in Async Method. image

And looking carefully you're changing the result type

Here is the original one returning Task:

public async Task<T> GetAsync<T>(IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false, IList<IProjection> colsToSelect = null, IList<IReferenceMap> includedProperties = null) where T : class
{
  return await Task.FromResult(InternalGet<T>(connection, id, transaction, commandTimeout, colsToSelect, includedProperties));
}

Here is your suggestion, returning T:

public async Task<T> GetAsync<T>(IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false, IList<IProjection> colsToSelect = null, IList<IReferenceMap> includedProperties = null) where T : class
{
    return (T)InternalGet<T>(connection, id, transaction, commandTimeout, colsToSelect, includedProperties);
}

It'll cause issues for those who are expecting a Task to get their results like this:

function MyItem Foo()
{
  var myResult := await conn.GetAsync<Entities.MyItem>(new { Id = pk });
 return myResult.Result;
}

What can be done is this:

public async Task<T> GetAsync<T>(IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false,
            IList<IProjection> colsToSelect = null, IList<IReferenceMap> includedProperties = null) where T : class
{
    return await Task.FromResult((T)InternalGet<T>(connection, id, transaction, commandTimeout, colsToSelect, includedProperties));
}

For the sync method the fix is ok

hfrances commented 3 years ago

Hello, thanks for your quick response. I have fixed my mistake in async methods according to your comment. This is the final code:

DapperExtensionsFixAsync-2

valfrid-ly commented 3 years ago

The change in DapperAsyncExtensions is unnecessary as "Instance.GetAsync" already returns Task<T>