Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dapper & MS Access - Read works, Write doesn't

Let's start by getting this out of the way: I'm stuck using an MS Access DB and I can't change it.

This works fine:

using (OleDbConnection conn = ConnectionHelper.GetConnection())
{
  conn.Open();
  var results = conn.Query<string>(
    "select FirstName from Students where LastName = @lastName", 
    new { lastName= "Smith" }
  );
  conn.Close();
}

This works fine:

using (OleDbConnection conn = ConnectionHelper.GetConnection())
{
  OleDbCommand cmd = new OleDbCommand(
    "update Students set FirstName = @firstName, City = @city where LastName = @lastName", 
    conn
  );
  cmd.Parameters.AddWithValue("firstName", "John");
  cmd.Parameters.AddWithValue("city", "SomeCity");
  cmd.Parameters.AddWithValue("lastName", "Smith");

  conn.Open();
  var result = cmd.ExecuteNonQuery();
  conn.Close();
}

This doesn't... it executes without error but it sets the FirstName as "SomeCity" in the DB and the City as "John":

using (OleDbConnection conn = ConnectionHelper.GetConnection())
{
  conn.Open();
  var results = conn.Query<string>(
    "update Students set FirstName = @firstName, City = @city where LastName = @lastName", 
    new { firstName = "John", city = "SomeCity", lastName = "Smith" }
  );
  conn.Close();
}

Any ideas?

EDIT BELOW

Dapper works if I use DynamicParameters:

using (OleDbConnection conn = ConnectionHelper.GetConnection())
{
  DynamicParameters parameters = new DynamicParameters();
  parameters.Add("firstName", "John");
  parameters.Add("city", "SomeCity");
  parameters.Add("lastName", "Smith");

  conn.Open();
  var result = conn.Query<string>(
    "update Students set FirstName = @firstName, City = @city where LastName = @lastName",
    parameters
  );
  conn.Close();
}
like image 311
Trev Avatar asked Sep 07 '12 16:09

Trev


People also ask

When should you use Dapper?

If your project prefers writing stored procedures or writing native query instead of using a full-fledged ORM tools like EntityFramework or NHibernate then Dapper is obvious choice for you. Using Dapper, it is very easy to fire a SQL query against database and get the result mapped to C# domain class.

Who Made Dapper?

Dapper is an object–relational mapping (ORM) product for the Microsoft .

Is Dapper any good?

Dapper is super awesome to handle complex queries that sport multiple joins and some real long business logic. Entity Framework Core is great for class generation, object tracking, mapping to multiple nested classes, and quite a lot more.

What is Dapper in .NET core?

Dapper is a simple Object Mapping Framework or a Micro-ORM that helps us to Map the Data from the Result of an SQL Query to a . NET Class efficiently. It would be as simple as executing a SQL Select Statement using the SQL Client object and returning the result as a Mapped Domain C# Class.


2 Answers

After some digging, I was able to find a cause:

Below is CreateParamInfoGenerator delegate from dapper's SqlMapper:

    public static Action<IDbCommand, object> CreateParamInfoGenerator(Identity identity)
    {

        // code above here
        IEnumerable<PropertyInfo> props = type.GetProperties().OrderBy(p => p.Name); 

The props is your unanimous param which gets re-ordered by OrderBy(p => p.Name), which moves city upfront.

new { firstName = "John", city = "SomeCity", lastName = "Smith" }

Props is then being added to the IDbCommand Parameters where the order is important.

If I comment out OrderBy() clause, then everything works.

I also tested DynamicParameters and intentionally re-ordered the attributes to move city upfront:

        var parameters = new DynamicParameters();
        parameters.Add("city", "SomeCity");
        parameters.Add("firstName", "John");
        parameters.Add("lastName", "Smith");

        var result = dbConnection.Query<string>(
          "update Students set FirstName = @firstName, City = @city where LastName = @lastName",
          parameters
        );

The above did not work as well, so the order of attributes is the reason!

I guess you can modify your local copy of SqlMapper for now and remove OrderBy() and wait for an official verdict from Marc...

Hope this helps.

like image 192
Void Ray Avatar answered Oct 28 '22 06:10

Void Ray


I had a similar issue, what I did was to use parameter names like @param1, @param2 instead of @name,@id,@price so the order stays the same without having to modify SQLMapper.cs file.

Something like

public void Update(Movie movie)
{
  var sql = "UPDATE myDB.movies set title=@param1, genre=@param2 where ID=@param3";
  db.Execute(sql, new { param1 = movie.Title, param2 = movie.Genre, param3 = movie.ID });
}
like image 26
Zo Has Avatar answered Oct 28 '22 04:10

Zo Has