Mam procedurę przechowywaną InsertCars
, która akceptuje listę zdefiniowanego przez użytkownika typu tabeli CarType
.Zadzwoń do procedury składowanej z dappera, która akceptuje listę zdefiniowanego przez użytkownika typu tabeli
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
Potrzebuję wywołać tę procedurę przechowywaną z Dappera. Przeszukałem go i znalazłem kilka rozwiązań.
var param = new DynamicParameters(new{CARID= 66, CARNAME= "Volvo"});
var result = con.Query("InsertCars", param, commandType: CommandType.StoredProcedure);
ale pojawia się błąd:
Procedure or function InsertCars has too many arguments specified
procedury przechowywanej także InsertCars
zwraca liczbę wstawionych wierszy; Potrzebuję uzyskać tę wartość.
Gdzie jest źródło problemu?
Mój problem polega również na tym, że mam samochody na ogólnej liście List<Car> Cars
i chcę przekazać tę listę do procedury przechowywania. Istnieje elegancki sposób, jak to zrobić?
public class Car
{
public CarId { get; set; }
public CarName { get; set; }
}
Dziękuję za pomoc
edytowany
znalazłem rozwiązań
Does Dapper support SQL 2008 Table-Valued Parameters?
lub
Does Dapper support SQL 2008 Table-Valued Parameters 2?
Więc spróbuj zrobić własnością głupich klasy pomocnika
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;
}
}
Korzystając
var result = con.Query("InsertCars", new CarDynamicParam(car), commandType: CommandType.StoredProcedure);
otrzymuję wyjątek
When using the multi-mapping APIs ensure you set the splitOn param if you have keys other than 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
Co jest nie tak?
FIXED:
połączeń con.Execute
zamiast con.Query
pierwszy problem ist przejścia parametr do procedury sklepu. Myślę, że liczenie i porządek są słuszne. Testuję moją procedurę za pomocą MS SQL Studio i działa dobrze. Zdefiniowany przez użytkownika typ tabeli ma tylko dwie kolumny: CARID i CARNAME. W DynamicParamater ustawiam tylko te dwie kolumny. Więc nie rozumiem, gdzie może być problem? – imodin
@Wobe wspomniałem o pełnym sposobie zrobienia tego. dla parametrów typu tabeli przekazuję datatable jako parametr, a nie parametr dyamiczny – Ehsan