小巧的参数不起作用

时间:2013-09-20 01:18:15

标签: c# dapper

我正在尝试使用Dapper orm以下简单查询:

var sqlString = new StringBuilder();
sqlString.Append("select a.acct AccountNumber,");
sqlString.Append("       b.first_name FirstName,");
sqlString.Append("       b.last_name LastName,");
sqlString.Append("       a.rr RrNumber,");
sqlString.Append("       c.addr1 AddressLine1,");
sqlString.Append("       c.addr2 AddressLine2,");
sqlString.Append("       c.addr3 AddressLine3,");
sqlString.Append("       c.addr4 AddressLine4,");
sqlString.Append("       c.addr5 AddressLine5,");
sqlString.Append("       c.addr6 AddressLine6,");
sqlString.Append("       c.addr7 AddressLine7,");
sqlString.Append("       c.addr8 AddressLine8 ");
sqlString.Append("from (pub.mfclac as a left join pub.mfcl as b on a.client=b.client) ");
sqlString.Append("left join pub.mfclad as c on a.client=c.client ");
sqlString.Append("where a.acct = '@ZYX'");

var connection = new OdbcConnection(_connectionString);

var result = connection.Query(sqlString.ToString(),
    new
    {
        ZYX = accountNumber
    });            

但是,当我使用已知存在的accountNumber执行此操作时,dapper不返回任何内容。因此,我尝试删除引号以验证参数实际上是否被帐号替换,但是从服务器返回的错误表示“@ZYX”周围的语法错误。这意味着dapper没有用它给定的值替换参数。任何想法为什么会这样?从有限的文档中,这应该“正常工作”。


EDIT1

无法让这个工作。使用string.format将参数作为解决方法插入。

2 个答案:

答案 0 :(得分:16)

这里有两个问题;首先(虽然你在你的问题中注意到这一点){1}},在SQL规则下,没有使用任何参数 - 它看起来匹配恰好包含where a.acct = '@ZYX'符号的文字字符串。对于SQL-Server(请参阅下面的注释),正确的用法是@

然而!由于您使用where a.acct = @ZYX,因此命名参数不适用。如果您实际连接到SQL-Server之类的东西,我强烈建议使用纯ADO.NET客户端,它们具有比ODBC更好的功能和性能。但是,如果ODBC是您唯一的选择:它不使用命名参数。直到几天前,这将代表一个主要问题,但根据Passing query parameters in Dapper using OleDb,代码(但尚未是NuGet包)现在支持ODBC。如果您从源构建(或等待下一个版本),您应该能够使用:

OdbcConnection
在您的命令中

,并且:

...
where a.acct = ?

请注意,ODBC不使用名称(var result = connection.Query(sqlString.ToString(), new { anythingYouLike = accountNumber }); ),因此可以... 您喜欢的任何内容。在更复杂的情况下,例如:

anythingYouLike

dapper使用一些关于如何实现匿名类型的知识来理解值的原始顺序,以便它们以正确的顺序添加到命令中.Execute(sql, new { id = 123, name = "abc", when = DateTime.Now }); id,{{1 }})。

最后一个观察结果:

  

这意味着dapper没有用它给定的值替换参数。

Dapper 从不用其给定值替换参数。这根本不是参数化sql的正确方法:参数通常是单独发送的,确保:

  • 没有SQL注入风险
  • 最大查询计划重复使用
  • 没有格式问题

请注意,某些ADO.NET / ODBC提供程序理论上可以选择通过替换在内部实现内容 - 但这与dapper是分开的。

答案 1 :(得分:0)

我是从双重问题Dapper must declare the scalar variable

着陆到这里的

错误:必须声明标量变量“ @Name”。

我用这段代码动态创建查询:

public static bool Insert<T>(T entity)
        {
            var tableName = entity.GetType().CustomAttributes.FirstOrDefault(x => x.AttributeType.Name == nameof(TableAttribute))?.ConstructorArguments?.FirstOrDefault().Value as string;
            if (string.IsNullOrEmpty(tableName))
                throw new Exception($"Cannot save {entity.GetType().Name}. Database models should have [Table(\"tablename\")] attribute.");
            DBSchema.TryGetValue(tableName.ToLower(), out var fields);
            using (var con = new SqlConnection(ConnectionString))
            {
                con.Open();

                var sql = $"INSERT INTO [{tableName}] (";
                foreach (var field in fields.Where(x => x != "id")) 
                {
                    sql += $"[{field}]"+",";
                }
                sql = sql.TrimEnd(',');
                sql += ")";
                sql += " VALUES (";
                foreach (var field in fields.Where(x => x != "id"))
                {
                    sql += "@"+field + ",";
                }
                sql = sql.TrimEnd(',');
                sql += ")";

                var affectedRows = con.Execute(sql, entity);
                return affectedRows > 0;
            }
        }

当我的模型是这样时,我遇到了相同的错误:

[Table("Users")]
public class User
{
   public string Name;
   public string Age;
}

我将它们更改为此:

[Table("Users")]
public class User
{
    public string Name { get; set; }
    public string Age { get; set; }
}

它为我解决了这个问题。