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);
}
CodePudding user response:
try this
return (await connection
.QueryAsync<T>(storedProcedure, parameters, commandType: CommandType.StoredProcedure))
.ToList();
CodePudding user response:
Because p1 is of a concrete type, whereas p2 is of type object (at runtime). So at run time, LoadData will be generic over the anonymous type or object respectively. Since object does not have any properties, that fails.
I suggest that to fix this you clone p2 to a concrete anonymous type before calling LoadData
var p2clone = new { foo = p2.foo ...};
var bar = LoadData(p2clone)
CodePudding user response:
p2
is dynamic
, which means that result2
is also dynamic, and FirstOrDefault
is an extension. Since the object type 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.