简体   繁体   中英

Can I remove a parameter from the Dapper DynamicParameters?

I am retrieving data from a external source. My class matches the response of the JSON. However there is an inner object inside the json. How can I remove it when I am passing it to the dynamic parameters in Dapper?

Basic structure of the class

{
   "name": "John",
   ... 30 more fields here ...

   "location": {
       "city": "abcd", 
       "zip": "87123"
    }
}

Using this like:

foreach (var result in response.results) 
{
    var parameters = new DynamicParameters();
    parameters.AddDynamicParams(result);

    // I need to remove "location" from this parameter
    // and then I can add the city and zip

    parameters.AddDynamicParams(result.location.city); // etc

    db.Execute("save_data", parameters, commandType:CommandType.StoredProcedure);
}

Still waiting for an answer, but here is the workaround I have started using

foreach (var result in response.results) {
  var parameters = new DynamicParameters();

  foreach (PropertyInfo prop in result.GetType().GetProperties()) {

      if (!SpecialParameter(result, prop, parameters))
         parameters.Add(prop.Name, prop.GetValue(result, null));

  }

  db.Execute("save_data",
         parameters, commandType: CommandType.StoredProcedure);
}    


function SpecialParameter(result, prop, parameters) {
// can be implemented in the sub class

   switch (prop.Name) {
      case "location":
         parameters.Add("location_city", result.city);
         parameters.Add("location_state", result.city);
         return true;
   }

  return false;
}

I wanted to be able to send Dapper strong types rather than anonymous objects, example:

var myObject = new MyClass{
  MyProperty = 1
};

_connection.ExecuteAsync(
  "InsertStoredProcedure",
  myObject,
  commandType: CommandType.StoredProcedure
)

That works just fine, but let's say MyClass has an Id int that gets auto-incremented in the database. I don't need to pass it in as an argument, and I don't want to have to update my stored procedure to take a dummy id argument that won't get used.

Fortunately Dapper's DynamicParameters constructor knows what to do if you give it a dictionary version of your object, so using reflection you can convert it to a dictionary, remove any fields you don't want, and then create a set of DynamicParameters from that.

Now the question is how to do that generically. If you have a lot of different entities that you want to use with Dapper, you don't want to have to convert them to dictionaries and remove the fields you don't want each time. You can solve that by making an attribute.

[AttributeUsage(AttributeTargets.Property)]
public class DapperIgnore : Attribute {}

Then decorate your class with the field(s) you want to ignore.

 public class MyClass {

   [DapperIgnore]
   public long Id {get; set;}

   public int MyProperty {get; set;}
 }

Now you can create an extension method that wraps the Dapper version.

public static async Task<int> ExecuteWithTypeAsync<TInput>(
  this IDbConnection cnn,
  string sql,
  TInput input,
  IDbTransaction transaction = null,
  int? commandTimeout commandTimeout = null,
  CommandType? commandType = null
){
   var dictionary = typeof(TInput).GetProperties()
     .Where(property => property
         .GetCustomAttributes(false)
         .All(attr => attr is not DapperIgnore)
     )
     .ToDictionary(x => x.Name, x => x.GetValue(input));

     var parameters = new DynamicParameters(dictionary);
     return await cnn.ExecuteAsync(sql, parameters, transaction, commandTimeout, commandType);
}

Note that you should name the method differently than the Dapper method it wraps--even though you've added a type argument--otherwise this will become the new method that is used everywhere, even with anonymous objects.

Now you can do

_connection.ExecuteWithTypeAsync(
  "InsertStoredProcedure",
  myObject,
  commandType: CommandType.StoredProcedure
)

...and it will not include the Id property that you decorated with the [DapperIgnore] attribute.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM