Вызовите хранимую процедуру из dapper, которая принимает список определенного типа таблицы
У меня есть хранимая процедура InsertCars
, которая принимает список определенного типа таблицы CarType
.
CREATE TYPE dbo.CarType
AS TABLE
(
CARID int null,
CARNAME varchar(800) not null,
);
CREATE PROCEDURE dbo.InsertCars
@Cars AS CarType READONLY
AS
-- RETURN COUNT OF INSERTED ROWS
END
Мне нужно вызвать эту хранимую процедуру из Dapper. Я искал ее и нашел некоторые решения.
var param = new DynamicParameters(new{CARID= 66, CARNAME= "Volvo"});
var result = con.Query("InsertCars", param, commandType: CommandType.StoredProcedure);
Но я получаю сообщение об ошибке:
Процедура или функция В InsertCars указано слишком много аргументов
Также хранимая процедура InsertCars
возвращает количество вставленных строк; Мне нужно получить это значение.
Где корень проблемы?
Моя проблема также в том, что у меня есть автомобили в общем списке List<Car> Cars
, и я хочу передать этот список для хранения процедуры. Он существует изящным способом, как это сделать?
public class Car
{
public CarId { get; set; }
public CarName { get; set; }
}
Спасибо за помощь
EDITED
Я нашел решения
Поддерживает ли Dapper табличные параметры SQL 2008?
или
Поддерживает ли Dapper SQL-таблицу с табличными параметрами 2?
Итак, я пытаюсь сделать собственный глупый вспомогательный класс
class CarDynamicParam : Dapper.SqlMapper.IDynamicParameters
{
private Car car;
public CarDynamicParam(Car car)
{
this.car = car;
}
public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
{
var sqlCommand = (SqlCommand)command;
sqlCommand.CommandType = CommandType.StoredProcedure;
var carList = new List<Microsoft.SqlServer.Server.SqlDataRecord>();
Microsoft.SqlServer.Server.SqlMetaData[] tvpDefinition =
{
new Microsoft.SqlServer.Server.SqlMetaData("CARID", SqlDbType.Int),
new Microsoft.SqlServer.Server.SqlMetaData("CARNAME", SqlDbType.NVarChar, 100),
};
var rec = new Microsoft.SqlServer.Server.SqlDataRecord(tvpDefinition);
rec.SetInt32(0, car.CarId);
rec.SetString(1, car.CarName);
carList.Add(rec);
var p = sqlCommand.Parameters.Add("Cars", SqlDbType.Structured);
p.Direction = ParameterDirection.Input;
p.TypeName = "CarType";
p.Value = carList;
}
}
Используйте
var result = con.Query("InsertCars", new CarDynamicParam(car), commandType: CommandType.StoredProcedure);
Я получаю исключение
При использовании API-интерфейсов множественного отображения убедитесь, что вы задали параметр splitOn, если у вас есть ключи, отличные от Id.
StackTrace:
at Dapper.SqlMapper.GetDynamicDeserializer(IDataRecord reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing) in c:\Dev\Dapper\Dapper\SqlMapper.cs:line 1308
at Dapper.SqlMapper.GetDeserializer(Type type, IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing) in c:\Dev\Dapper\Dapper\SqlMapper.cs:line 1141
at Dapper.SqlMapper.<QueryInternal>d__d`1.MoveNext() in c:\Dev\Dapper\Dapper\SqlMapper.cs:line 819
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable`1 commandTimeout, Nullable`1 commandType) in c:\Dev\Dapper\Dapper\SqlMapper.cs:line 770
at Dapper.SqlMapper.Query(IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable`1 commandTimeout, Nullable`1 commandType) in c:\Dev\Dapper\Dapper\SqlMapper.cs:line 715
Что не так?
ИСПРАВЛЕНО:
Вызов con.Execute
вместо con.Query
Ответы
Ответ 1
Моя проблема также в том, что у меня есть автомобили в общем списке Список автомобилей, и я хочу передать этот список для хранения процедуры. Он существует изящным способом, как это сделать?
Вам нужно преобразовать свой общий список Car в datatable, а затем передать его на сохраненную процедуру. Следует отметить, что порядок ваших полей должен быть таким же, как определенный в пользовательском типе таблицы в базе данных. В противном случае данные не будут сохранены должным образом. И он должен иметь одинаковое количество столбцов.
Я использую этот метод для преобразования List в DataTable. Вы можете называть его как yourList.ToDataTable()
public static DataTable ToDataTable<T>(this List<T> iList)
{
DataTable dataTable = new DataTable();
PropertyDescriptorCollection propertyDescriptorCollection =
TypeDescriptor.GetProperties(typeof(T));
for (int i = 0; i < propertyDescriptorCollection.Count; i++)
{
PropertyDescriptor propertyDescriptor = propertyDescriptorCollection[i];
Type type = propertyDescriptor.PropertyType;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
type = Nullable.GetUnderlyingType(type);
dataTable.Columns.Add(propertyDescriptor.Name, type);
}
object[] values = new object[propertyDescriptorCollection.Count];
foreach (T iListItem in iList)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = propertyDescriptorCollection[i].GetValue(iListItem);
}
dataTable.Rows.Add(values);
}
return dataTable;
}
Ответ 2
Я знаю, что это немного старо, но я думал, что буду публиковать на этом, так как я искал, чтобы сделать это немного легче. Надеюсь, я сделал это с созданным пакетом NuGet, который позволит использовать код:
public class CarType
{
public int CARID { get; set; }
public string CARNAME{ get; set; }
}
var cars = new List<CarType>{new CarType { CARID = 1, CARNAME = "Volvo"}};
var parameters = new DynamicParameters();
parameters.AddTable("@Cars", "CarType", cars)
var result = con.Query("InsertCars", parameters, commandType: CommandType.StoredProcedure);
Пакет NuGet: https://www.nuget.org/packages/Dapper.ParameterExtensions/0.2.0
Все еще на ранних этапах, поэтому, возможно, не все будет работать!
Прочитайте README и не стесняйтесь вносить вклад в GitHub: https://github.com/RasicN/Dapper-Parameters
Ответ 3
Другим решением было бы назвать это следующим образом:
var param = new DynamicParameters(new{CARID= 66, CARNAME= "Volvo"});
var result = con.Query<dynamic>("InsertCars", param);
Удалить: новый CarDynamicParam (автомобиль), commandType: CommandType.StoredProcedure
Используйте параметр типа таблицы напрямую, он будет работать.
Если вы можете использовать Datatable (ядро netnet не поддерживает его), то это очень просто.
Создать DataTable → Добавить необходимые столбцы для соответствия типу таблицы → Добавить обязательные строки. Наконец просто назовите его, используя dapper, как это.
var result = con.Query<dynamic>("InsertCars", new{paramFromStoredProcedure=yourDataTableInstance}, commandType: CommandType.StoredProcedure);