【问题标题】:Does Dapper support SQL 2008 Table-Valued Parameters 2?Dapper 是否支持 SQL 2008 表值参数 2?
【发布时间】:2011-10-18 07:43:39
【问题描述】:

我知道 dapper 可以支持 TVF,但是如何发送额外的参数以及 TVF(不将其添加到 IntDynamicParam 类)?请参阅 Tests.cs 中的以下示例,我已修改以添加额外参数:

connection.Execute("CREATE TYPE int_list_type AS TABLE (n int NOT NULL PRIMARY KEY)");
connection.Execute("CREATE PROC get_ints @x int, @ints int_list_type READONLY AS select * from @ints");

我尝试了以下方法,但出现错误(不存在从对象类型 SqlMapper.Tests+IntDynamicParam 到已知托管提供程序本机类型的映射。):

var p = new DynamicParameters();
p.Add("x", 4);
p.Add("ints",new IntDynamicParam(new int[] { 1, 2, 3 }));

var nums = connection.Query<int>("get_ints", p).ToList();

感谢 Sam 的回复,但问题有点不同。我想知道如何将另一个变量与元组一起传递。见下方修改后的SP:

CREATE TYPE int_tuple_list_type AS TABLE (n int NOT NULL PRIMARY KEY, n2 int)

CREATE PROC get_int_tuples 
  @someVar varchar(10),
  @ints int_tuple_list_type READONLY
AS select * from @ints

【问题讨论】:

  • 我知道这是我们看过的东西,但目前我不记得它的当前状态。我将不得不检查代码。 IIRC 我们出于使用(性能)的考虑而决定反对它,但我们可能会让代码乱七八糟。我稍后会检查。
  • 你有什么更新吗?

标签: c# model-view-controller orm dapper


【解决方案1】:

IDynamicParameters 几乎没有什么魔力,您只需担心在准备好运行打开的 IDbCommand 时实现AddParameters

假设你想要一个整数元组,你可以实现以下内容:

CREATE TYPE int_tuple_list_type 
     AS TABLE (n int NOT NULL PRIMARY KEY, n2 int)
CREATE PROC get_int_tuples @ints 
     int_tuple_list_type READONLY AS select * from @ints

后跟:

class TupleIntDynamicParam : Dapper.SqlMapper.IDynamicParameters
{
    IEnumerable<int> tuples;
    public IntDynamicParam(IEnumerable<Tuple<int,int>> tuples)
    {
        this.tuples= tuples;
    }

    public void AddParameters(IDbCommand command)
    {
        var sqlCommand = (SqlCommand)command;
        sqlCommand.CommandType = CommandType.StoredProcedure;

        List<Microsoft.SqlServer.Server.SqlDataRecord> number_list = 
           new List<Microsoft.SqlServer.Server.SqlDataRecord>();

        // Create an SqlMetaData object that describes our table type.
        Microsoft.SqlServer.Server.SqlMetaData[] tvp_definition = { 
          new Microsoft.SqlServer.Server.SqlMetaData("n", SqlDbType.Int), 
          new Microsoft.SqlServer.Server.SqlMetaData("n2", SqlDbType.Int) };

        foreach (int n in tuples)
        {
            // Create a new record, using the metadata array above.
            Microsoft.SqlServer.Server.SqlDataRecord rec = 
                new Microsoft.SqlServer.Server.SqlDataRecord(tvp_definition);
            rec.SetInt32(0, n.Item1);
            rec.SetInt32(1, n.Item2);
            number_list.Add(rec);      // Add it to the list.
        }

        // Add the table parameter.
        var p = sqlCommand.Parameters.Add("ints", SqlDbType.Structured);
        p.Direction = ParameterDirection.Input;
        p.TypeName = "int_tuple_list_type";
        p.Value = number_list;

    }
}

然后你可以传入元组:

var nums = connection.Query("get_int_tuples", 
      new TupleIntDynamicParam (new Tuple<int,int>[] 
      { 
           Tuple.Create(1,2), Tuple.Create(2,3) 
      })).ToList();

【讨论】:

  • 您将如何将其他参数与 TVP 一起传递?
  • 为什么是Parameters.Add而不是Parameters.AddWithValue?不是反问,我在这里遇到了麻烦
【解决方案2】:

如果您从 DynamicParameters 派生自定义类并实现 IDynamicParameters,则可以解决上述问题。

public class DynamicParametersWithTVP : Dapper.DynamicParameters, Dapper.SqlMapper.IDynamicParameters
{

.....

我写了一个通用类,可以让你像这样调用 proc:

        var procParams = new DynamicParametersWithTVP();
        procParams.Add("@Param1", someValue);
        procParams.Add("@Param2", someOtherValue);
        procParams.AddTVP("@TableParam1", "dbo.someTableType", someEnumberableListOfObject);

【讨论】:

  • 您有更多自定义类的示例吗?我正在努力实现这一目标。
  • 为什么不分享问题的答案?
【解决方案3】:

这就是我使用泛型类的方式。这还不完美。将在我对其进行更改时更新此帖子。

public class TableTypeDynamicParam<T> : Dapper.SqlMapper.IDynamicParameters
{
    IEnumerable<T> MyList;
    Dictionary<string, int> ordinals;
    Dictionary<Type, SqlDbType> typeMap;
    string ParameterName, TableTypeName;
    public TableTypeDynamicParam(IEnumerable<T> listValue, string parameterName, string tableTypeName)
    {
        this.MyList = listValue;
        this.ParameterName = parameterName;
        this.TableTypeName = tableTypeName;
        ordinals = new Dictionary<string, int>();
        SetTypeMap();
    }

    void SetTypeMap()
    {
        typeMap = new Dictionary<Type, SqlDbType>();
        typeMap[typeof(byte)] = SqlDbType.TinyInt;
        typeMap[typeof(sbyte)] = SqlDbType.TinyInt;
        typeMap[typeof(short)] = SqlDbType.SmallInt;
        typeMap[typeof(ushort)] = SqlDbType.SmallInt;
        typeMap[typeof(int)] = SqlDbType.Int;
        typeMap[typeof(uint)] = SqlDbType.Int;
        typeMap[typeof(long)] = SqlDbType.Int;
        typeMap[typeof(ulong)] = SqlDbType.BigInt;
        typeMap[typeof(float)] = SqlDbType.Float;
        typeMap[typeof(double)] = SqlDbType.Float;
        typeMap[typeof(decimal)] = SqlDbType.Decimal;
        typeMap[typeof(bool)] = SqlDbType.Bit;
        typeMap[typeof(string)] = SqlDbType.Text;
        typeMap[typeof(char)] = SqlDbType.Char;
        typeMap[typeof(Guid)] = SqlDbType.UniqueIdentifier;
        typeMap[typeof(DateTime)] = SqlDbType.DateTime;
        typeMap[typeof(DateTimeOffset)] = SqlDbType.DateTimeOffset;
        typeMap[typeof(byte[])] = SqlDbType.Binary;
        typeMap[typeof(byte?)] = SqlDbType.TinyInt;
        typeMap[typeof(sbyte?)] = SqlDbType.TinyInt;
        typeMap[typeof(short?)] = SqlDbType.SmallInt;
        typeMap[typeof(ushort?)] = SqlDbType.SmallInt;
        typeMap[typeof(int?)] = SqlDbType.Int;
        typeMap[typeof(uint?)] = SqlDbType.Int;
        typeMap[typeof(long?)] = SqlDbType.BigInt;
        typeMap[typeof(ulong?)] = SqlDbType.BigInt;
        typeMap[typeof(float?)] = SqlDbType.Float;
        typeMap[typeof(double?)] = SqlDbType.Float;
        typeMap[typeof(decimal?)] = SqlDbType.Decimal;
        typeMap[typeof(bool?)] = SqlDbType.Bit;
        typeMap[typeof(char?)] = SqlDbType.Char;
        typeMap[typeof(Guid?)] = SqlDbType.UniqueIdentifier;
        typeMap[typeof(DateTime?)] = SqlDbType.DateTime;
        typeMap[typeof(DateTimeOffset?)] = SqlDbType.DateTimeOffset;
        //  typeMap[typeof(System.Data.Linq.Binary)] = SqlDbType.Binary;
    }

    SqlDbType GetSqlDBType(Type t)
    {

        # region other tries

        /*  SqlParameter p1 = new SqlParameter();

             TypeConverter tc = TypeDescriptor.GetConverter(p1.DbType);
             if (tc.CanConvertFrom(theType))
                 p1.DbType = (DbType)tc.ConvertFrom(theType.Name);
             else
             {
                 //Try brute force
                 try
                 {
                     p1.DbType = (DbType)tc.ConvertFrom(theType.Name);
                 }
                 catch {} //Do Nothing
             }
             return p1.SqlDbType; 
             Microsoft.SqlServer.Server.SqlMetaData sm = Microsoft.SqlServer.Server.SqlMetaData.InferFromValue(new byte[] { 1, 2 }, "someName");
sm = Microsoft.SqlServer.Server.SqlMetaData.InferFromValue(2.3, "someName");
sm = Microsoft.SqlServer.Server.SqlMetaData.InferFromValue(11, "someName");
sm =     Microsoft.SqlServer.Server.SqlMetaData.InferFromValue(System.Web.HttpValidationStatus.Valid, "someName");
sm = Microsoft.SqlServer.Server.SqlMetaData.InferFromValue("hello", "someName");

Console.WriteLine(sm.SqlDbType);
Console.WriteLine(sm.TypeName);
Console.WriteLine(sm.MaxLength);

             */
        # endregion

        return typeMap[t];

    }

    void SetRecordValue(ref Microsoft.SqlServer.Server.SqlDataRecord rec, string propertyName, object value, Type propertyType)
    {
        switch (propertyType.ToString())
        {
            //need to cover all type case
            case "System.Int32":
                rec.SetInt32(ordinals[propertyName], (int)value);
                break;
            case "System.Int64":
                rec.SetInt64(ordinals[propertyName], (long)value);
                break;
            case "System.Boolean":
                rec.SetBoolean(ordinals[propertyName], (bool)value);
                break;
            case "System.String":
            default:
                rec.SetString(ordinals[propertyName], Convert.ToString(value));
                break;
        }
    }

    public void AddParameters(IDbCommand command)
    {
        var sqlCommand = (SqlCommand)command;
        sqlCommand.CommandType = CommandType.StoredProcedure;

        List<Microsoft.SqlServer.Server.SqlDataRecord> tableType_list = new List<Microsoft.SqlServer.Server.SqlDataRecord>();
        var first = MyList.FirstOrDefault();
        if (null != first)
        {
            var lstDefinition = new List<Microsoft.SqlServer.Server.SqlMetaData>();
            int i = 0;
            foreach (var prop in first.GetType().GetProperties())
            {
                lstDefinition.Add(new Microsoft.SqlServer.Server.SqlMetaData(prop.Name, GetSqlDBType(prop.PropertyType)));
                ordinals.Add(prop.Name, i++);
            }
            // Create an SqlMetaData object that describes our table type.
            // Microsoft.SqlServer.Server.SqlMetaData[] tvp_definition = { new Microsoft.SqlServer.Server.SqlMetaData("n", SqlDbType.Int) };

            foreach (var l in MyList)
            {
                // Create a new record, using the metadata array above.
                Microsoft.SqlServer.Server.SqlDataRecord rec = new Microsoft.SqlServer.Server.SqlDataRecord(lstDefinition.ToArray());
                foreach (var prop in first.GetType().GetProperties())
                {

                    // rec.SetInt32(ordinals[prop.Name], prop.GetValue(l));    // Set the value.
                    SetRecordValue(ref rec, prop.Name, prop.GetValue(l), prop.GetType());
                }
                tableType_list.Add(rec);      // Add it to the list.
            }
        }

        // Add the table parameter.
        var p = sqlCommand.Parameters.Add("@" + ParameterName.TrimStart('@'), SqlDbType.Structured);
        p.Direction = ParameterDirection.Input;
        p.TypeName = TableTypeName;
        if (null != first)
            p.Value = tableType_list;
        else
            p.Value = DBNull.Value;

    }

    public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
    {
        AddParameters(command);
    }
}

【讨论】:

    【解决方案4】:

    我还需要能够传递表值参数和常规参数。结合@Esen 和@Roger-Joys 的答案给了我下面的课程。此类专门针对使用 stringlist_to_table 类型,但您可以更改它以满足您的需要。对您要处理的每种 TVP 类型都有一个特定的方法对我来说似乎很有意义。

    CREATE TYPE stringlist_tbltype AS TABLE (s VARCHAR(256))
    

    用法:

    var p = new DynamicParametersWithTVP();
    p.Add( "@someVar", "abc", DbType.AnsiString );
    p.AddTVPString( "@stringlist", new string[] { "abc", "def" } );
    
    using (var conn = new SqlConnection( _cs )) {
        conn.Open();
        return conn.Query( "dbo.stored_proc_name", p, commandType: CommandType.StoredProcedure );
    }
    

    这里是 DynamicParametersWithTVP 的实现。它基本上保留了一个 DynamicParameters 类来处理非 TVP 的东西,以及 TVP 的构建。

    class DynamicParametersWithTVP : SqlMapper.IDynamicParameters
    {
        private Dictionary<string, TVPData> _tvpParams;
        private DynamicParameters _params;
    
        public DynamicParametersWithTVP()
        {
            _tvpParams = new Dictionary<string, TVPData>();
            _params = new DynamicParameters();
        }
    
        public void Add( string name, object value = null, DbType? dbType = null, ParameterDirection? direction = null, int? size = null )
        {
            _params.Add( name, value, dbType, direction, size );
        }
    
        public void AddTVPString( string name, IEnumerable<string> values )
        {
            var metadata = new[] {
                new SqlMetaData( "one", SqlDbType.VarChar, 256)
            };
    
            var data = new TVPData
            {
                Data = values,
                MetaData = metadata,
                Name = name,
                Type = "stringlist_tbltype",
                SetData = ( rec, s ) => rec.SetString( 0, (string)s ),
            };
    
            _tvpParams.Add( name, data );
        }
    
        public void AddParameters( IDbCommand command, SqlMapper.Identity identity )
        {
            //Adds the regular parameters, then adds any tvp parameters
            ((SqlMapper.IDynamicParameters)_params).AddParameters( command, identity );
            AddTVPCommands( command );
        }
    
        private void AddTVPCommands( IDbCommand command )
        {
            foreach (var o in _tvpParams) {
                AddTVPParam( command, o.Key, o.Value );
            }
        }
    
        private void AddTVPParam( IDbCommand command, string name, TVPData value )
        {
            var dataList = new List<SqlDataRecord>();
            if (value.Data != null) {
                foreach (var d in value.Data) {
                    var rec = new SqlDataRecord( value.MetaData );
                    value.SetData( rec, d ); //note: this only works for a one-column TVP
                    dataList.Add( rec );
                }
            }
            if (dataList.Count == 0) { //gotta make the value null if there isn't any data.
                dataList = null;
            }
    
            var p = ((SqlCommand)command).Parameters.Add( name, SqlDbType.Structured );
            p.Direction = ParameterDirection.Input;
            p.TypeName = value.Type;
            p.Value = dataList;
        }
    
        private class TVPData
        {
            public string Name { get; set; }
            public string Type { get; set; }
            public SqlMetaData[] MetaData { get; set; }
            public IEnumerable Data { get; set; }
            public Action<SqlDataRecord, object> SetData { get; set; }
        }
    }
    

    【讨论】:

      【解决方案5】:

      这是一个完整的解决方案,使用ICustomQueryParameter 接口和我编写的一些代码(在附加页面的底部)让您使用 dapper 将任何 IEnumerable 发送到存储过程,即使 T 具有多个属性:

      http://code.google.com/p/dapper-dot-net/issues/detail?can=2&start=0&num=100&q=ICustomQueryParameter&colspec=ID%20Type%20Status%20Priority%20Milestone%20Owner%20Summary&groupby=&sort=&id=69

      这是链接中的代码:

        /// <summary>
          /// Send DataTable as dapper parameter
          /// </summary>
          public class DapperTableParameter : ICustomQueryParameter
          {
              protected DataTable _table = null;
      
              public DapperTableParameter(DataTable table)
              {
                  _table = table;
              }
      
              public void AddParameter(System.Data.IDbCommand command, string name)
              {
                  // This is SqlConnection specific
                  ((SqlCommand)command).Parameters.Add("@" + name, SqlDbType.Structured).Value = _table;
              }
          }
      
      
      
      public class DapperTVP<T> : DapperTableParameter
          {
              public DapperTVP(IEnumerable<T> list) : base(new System.Data.DataTable())
              {
                  var t = typeof(T);
                  var propertyByName = new Dictionary<string, PropertyInfo>();
      
                  foreach (var p in t.GetProperties())
                  {
                      propertyByName.Add(p.Name, p);
                      _table.Columns.Add(p.Name, p.PropertyType);
                  }
      
                  foreach (var i in list)
                  {
                      var row = _table.NewRow();
                      foreach (var p in propertyByName)
                      {
                          row[p.Key] = p.Value.GetValue(i, null);
                      }
      
                      _table.Rows.Add(row);
                  }
              }
          }
      

      你仍然需要像这样合并ICustomQueryParameterhttp://code.google.com/p/dapper-dot-net/issues/attachmentText?id=69&aid=690000000&name=SqlMapper.patch&token=wFLdWLM4LPamcAwcDaGqcITaAmg%3A1392913796708

      【讨论】:

      • 你能提供一个使用例子吗?
      【解决方案6】:

      我更喜欢这样做:

      internal class TableTypeDynamicParam : SqlMapper.IDynamicParameters {
          protected readonly List<object> Lst = new List<object>();
          protected SqlCommand Cmd;
          public void Add(DataTable dt) {
              if(dt != null)
                  Lst.Add(dt);
          }
      
          public void Add(DataSet ds) {
              if(ds != null)
                  foreach(DataTable dt in ds.Tables) {
                      Lst.Add(dt);
                  }
          }
      
          public void Add(string name, object value = null, SqlDbType? dbType = null, ParameterDirection direction = ParameterDirection.Input, int? size = null) {
              var par = value != null ? new SqlParameter(name, value) : new SqlParameter(name, dbType);
              par.Direction = direction;
              if(size.HasValue)
                  par.Size = size.Value;
              Lst.Add(par);
          }
      
          public void Add(SqlParameter par) {
              Lst.Add(par);
          }
      
          public void AddRange(IEnumerable<SqlParameter> pars) {
              if(pars != null)
                  Lst.AddRange(pars);
          }
      
          public void AddParameters(IDbCommand command) {
              Cmd = (SqlCommand)command;
      
              foreach(var o in Lst) {
                  var dt = o as DataTable;
                  if(dt != null) {
                      var parameter = Cmd.Parameters.AddWithValue(dt.ExtendedProperties["parameterName"].ToString(), dt);
                      parameter.SqlDbType = SqlDbType.Structured;
                      parameter.TypeName = dt.TableName;
                  } else {
                      var par = o as SqlParameter;
                      if(par != null)
                          Cmd.Parameters.Add(par);
                  }
              }
          }
      
          public void AddParameters(IDbCommand command, SqlMapper.Identity identity) {
              AddParameters(command);
          }
      
          public T Get<T>(string name) {
              return (T)Cmd.Parameters[name].Value;
          }
      
          public ERPDictionay GetLst(ERPLst<SqlParameter> pars) {
              var dic = new ERPDictionay();
              if(pars != null) {
                  dic.QtdItemsPageParameterName = pars.QtdItemsPageParameterName;
                  dic.QtdItemsPage = pars.QtdItemsPage;
                  dic.CurrentPageParameterName = pars.CurrentPageParameterName;
                  dic.CurrentPage = pars.CurrentPage;
              };
              for(var i = 0; i < Cmd.Parameters.Count; i++) {
                  var a = Cmd.Parameters[i];
                  if (a.Direction != ParameterDirection.InputOutput && a.Direction != ParameterDirection.Output) continue;
                  if(pars != null && a.ParameterName == pars.TotalItensDBParameterName) {
                      dic.TotalItensDB = Convert.ToInt32(Cmd.Parameters[i].Value);
                  } else {
                      dic.Add(a.ParameterName, Cmd.Parameters[i].Value);
                  }
              }
              return dic;
          }
      }
      
      internal class TableTypeDynamicParam<T> : TableTypeDynamicParam
      {
          private ERPLstInput<T> _lstItems;
      
          public void Add(ERPLstInput<T> lstItems)
          {
              if (lstItems != null)
                  _lstItems = lstItems;
          }
      
          private static Dictionary<Type, SqlDbType> _typeMap;
      
          private static Dictionary<Type, SqlDbType> TypeMap
          {
              get
              {
                  if (_typeMap != null)
                      return _typeMap;
                  _typeMap = new Dictionary<Type, SqlDbType>();
                  _typeMap[typeof(byte)] = SqlDbType.TinyInt;
                  _typeMap[typeof(sbyte)] = SqlDbType.TinyInt;
                  _typeMap[typeof(short)] = SqlDbType.SmallInt;
                  _typeMap[typeof(ushort)] = SqlDbType.SmallInt;
                  _typeMap[typeof(int)] = SqlDbType.Int;
                  _typeMap[typeof(uint)] = SqlDbType.Int;
                  _typeMap[typeof(long)] = SqlDbType.Int;
                  _typeMap[typeof(ulong)] = SqlDbType.BigInt;
                  _typeMap[typeof(float)] = SqlDbType.Float;
                  _typeMap[typeof(double)] = SqlDbType.Float;
                  _typeMap[typeof(decimal)] = SqlDbType.Decimal;
                  _typeMap[typeof(bool)] = SqlDbType.Bit;
                  _typeMap[typeof(string)] = SqlDbType.Text;
                  _typeMap[typeof(char)] = SqlDbType.Char;
                  _typeMap[typeof(Guid)] = SqlDbType.UniqueIdentifier;
                  _typeMap[typeof(DateTime)] = SqlDbType.DateTime;
                  _typeMap[typeof(DateTimeOffset)] = SqlDbType.DateTimeOffset;
                  _typeMap[typeof(byte[])] = SqlDbType.Binary;
                  _typeMap[typeof(byte?)] = SqlDbType.TinyInt;
                  _typeMap[typeof(sbyte?)] = SqlDbType.TinyInt;
                  _typeMap[typeof(short?)] = SqlDbType.SmallInt;
                  _typeMap[typeof(ushort?)] = SqlDbType.SmallInt;
                  _typeMap[typeof(int?)] = SqlDbType.Int;
                  _typeMap[typeof(uint?)] = SqlDbType.Int;
                  _typeMap[typeof(long?)] = SqlDbType.BigInt;
                  _typeMap[typeof(ulong?)] = SqlDbType.BigInt;
                  _typeMap[typeof(float?)] = SqlDbType.Float;
                  _typeMap[typeof(double?)] = SqlDbType.Float;
                  _typeMap[typeof(decimal?)] = SqlDbType.Decimal;
                  _typeMap[typeof(bool?)] = SqlDbType.Bit;
                  _typeMap[typeof(char?)] = SqlDbType.Char;
                  _typeMap[typeof(Guid?)] = SqlDbType.UniqueIdentifier;
                  _typeMap[typeof(DateTime?)] = SqlDbType.DateTime;
                  _typeMap[typeof(DateTimeOffset?)] = SqlDbType.DateTimeOffset;
                  return _typeMap;
              }
          }
      
          static SqlDbType GetSqlDBType(Type t) {
              return TypeMap[t];
          }
      
          void SetRecordValue(ref SqlDataRecord rec, string propertyName, object value, Type propertyType) {
              switch(propertyType.ToString()) {
                  case "System.Int32":
                      rec.SetInt32(def.IndexOf(a=>a.Name == propertyName), (int)value);
                      break;
                  case "System.Int64":
                      rec.SetInt64(def.IndexOf(a => a.Name == propertyName), (long)value);
                      break;
                  case "System.Boolean":
                      rec.SetBoolean(def.IndexOf(a => a.Name == propertyName), (bool)value);
                      break;
                  case "System.String":
                  default:
                      rec.SetString(def.IndexOf(a => a.Name == propertyName), Convert.ToString(value));
                      break;
              }
          }
      
          private List<SqlMetaData> def;
          public new void AddParameters(IDbCommand command) {
              Cmd = (SqlCommand)command;
      
              foreach(var o in Lst) {
                  var dt = o as DataTable;
                  if(dt != null) {
                      var parameter = Cmd.Parameters.AddWithValue(dt.ExtendedProperties["parameterName"].ToString(), dt);
                      parameter.SqlDbType = SqlDbType.Structured;
                      parameter.TypeName = dt.TableName;
                  } else {
                      var par = o as SqlParameter;
                      if(par != null)
                          Cmd.Parameters.Add(par);
                  }
              }
      
              if (_lstItems != null)
              {
                  var tableTypeList = new List<SqlDataRecord>();
                  var first = _lstItems.FirstOrDefault();
                  if (first != null)
                  {
                      def = new List<SqlMetaData>();
                      int i = 0;
                      foreach (var prop in first.GetType().GetProperties())
                      {
                          def.Add(new SqlMetaData(prop.Name, GetSqlDBType(prop.PropertyType)));
                      }
                      foreach (var l in _lstItems)
                      {
                          var rec = new SqlDataRecord(def.ToArray());
                          foreach (var prop in first.GetType().GetProperties())
                          {
                              SetRecordValue(ref rec, prop.Name, prop.GetValue(l), prop.GetType());
                          }
                          tableTypeList.Add(rec);
                      }
                  }
      
                  var p = Cmd.Parameters.Add("@" + _lstItems.ParameterName.TrimStart('@'), SqlDbType.Structured);
                  p.Direction = ParameterDirection.Input;
                  p.TypeName = _lstItems.TableTypeName;
                  if (null != first)
                      p.Value = tableTypeList;
                  else
                      p.Value = DBNull.Value;
              }
          }
      }
      

      字典是这样的:

      [Serializable]
      public class ERPDictionay : Dictionary<string,object> {
      
          private string _currentPageParameterName = "@currentPage";
          public string CurrentPageParameterName {
              get { return _currentPageParameterName; }
              set { _currentPageParameterName = value; }
          }
      
          private string _qtdItemsPageParameterName = "@qtdItemsPage";
          public string QtdItemsPageParameterName {
              get { return _qtdItemsPageParameterName; }
              set { _qtdItemsPageParameterName = value; }
          }
      
          private string _totalItensDBParameterName = "@totalItensDB";
          public string TotalItensDBParameterName {
              get { return _totalItensDBParameterName; }
              set { _totalItensDBParameterName = value; }
          }
      
          public int CurrentPage { get; set; }
          public int QtdItemsPage { get; set; }
          public int TotalItensDB { get; set; }
      
          public ERPDictionay() { }
      
          public ERPDictionay(
              int qtdItemsPage,
              int currentPage = 0,
              string currentPageParameterName = null,
              string qtdItemsPageParameterName = null,
              string totalItensDBParameterName = null)
          {
              QtdItemsPage = qtdItemsPage;
              CurrentPage = currentPage;
              if (!string.IsNullOrEmpty(currentPageParameterName))
                  _currentPageParameterName = currentPageParameterName;
              if(!string.IsNullOrEmpty(qtdItemsPageParameterName))
                  _qtdItemsPageParameterName = qtdItemsPageParameterName;
              if(!string.IsNullOrEmpty(totalItensDBParameterName))
                  _totalItensDBParameterName = totalItensDBParameterName;
          }
      }
      

      【讨论】:

      • 请注意 - 似乎缺少 ERPLst 和 ERPLstInput 的定义。
      【解决方案7】:

      有一个 nuget 包,Dapper TVP,其中包含一些使使用表值参数更容易的类。

      需要注意的是,该包依赖于 Dapper 1.12.1 或更高版本。

      使用此包将 tvp 传递给存储过程如下所示:

              var p = new Dapper.Tvp.DynamicParametersTvp();
      
              SqlMetaData[] tableValuedParameterDefinition = 
              { 
                  new SqlMetaData("columnOne", SqlDbType.UniqueIdentifier), 
                  new SqlMetaData("columnTwo", SqlDbType.VarBinary, 64)
              };
      
              var collectionRows = new List<SqlDataRecord>();
      
              for (int i = 0; i < collection.Count; i++)
              {
                  var row = new SqlDataRecord(tableValuedParameterDefinition);
                  row.SetGuid(0, collection[i].Item1);
                  row.SetBytes(1, 0, collection[i].Item2, 0, sessionsAndPins[i].Item2.Length);
                  collectionRows.Add(row);
              }
      
              p.Add(new Dapper.Tvp.TableValueParameter("@tvpName", "tvpTypeName", collectionRows));
      
              using (SqlConnection connection = new SqlConnection(ConnectionManager.GetConnectionString("Database")))
              {
                  try
                  {
                      connection.Open();
      
                      result = connection.Query<SomeObject>("SomeStoredProcedureThatExpectsTVP", p, commandType: CommandType.StoredProcedure).SingleOrDefault();
                  }
                  finally
                  {
                      connection.Close();
                  }
              }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-22
        • 1970-01-01
        • 2011-08-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多