I don't know why the return value of the LoadData function (shown below) in one case supports the FirstOrDefault() method and in another case doesn't. In both cases it is the same return type.
The only difference is the way in which the dynamic parameter is created.
public async Task<LookupModel?> UpdateLookup(LookupModel item, Guid newUk)
var p1 = new
{
item.Code,
item.Name,
item.uk,
newUk
};
var result1 = await _db.LoadData<LookupModel, dynamic>("lu.Lookup_Update", p1);
// result1.GetType() = System.Collections.Generic.List`1[DataAccess.Models.Lookups.LookupModel]
var rtv1 = result1.FirstOrDefault(); // ok
var p2 = item.GetUpdateParams(newUk);
var result2 = await _db.LoadData<LookupModel, dynamic>("lu.Lookup_Update", p2);
// result2.GetType() = System.Collections.Generic.List`1[DataAccess.Models.Lookups.LookupModel]
var rtv2 = result2.FirstOrDefault(); // not ok
// This throws an exception as FirstOrDefault() is not defined
return rtv1;
}
// LookupModel
public dynamic GetUpdateParams(Guid newUk)
{
return new
{
this.Code,
this.Name,
this.uk,
newUK
};
}
// LoadData
public async Task<IEnumerable<T>> LoadData<T, U>(string storedProcedure, U parameters, string connectionId = "Default")
{
using IDbConnection connection = new SqlConnection(_config.GetConnectionString(connectionId));
return await connection.QueryAsync<T>(storedProcedure, parameters, commandType: CommandType.StoredProcedure);
}
p2
is dynamic
, which means that result2
is also dynamic (since it takes p2
as an input), and FirstOrDefault
is an extension method. Since the type of result2
is not known at compile time, you can't call an extension method on it.
You can still do this by using the actual static method instead of an extension method:
var rtv2 = Enumerable.FirstOrDefault(result2);
since the static method can be bound at run-time.
But I would just change GetUpdateParams
so that it returns a named type rather than an anonymous type, and then you don't have to use dynamic
. That will also get you more type safety since the compiler can do type checking and you don't have to wait until runtime to find type errors.