Sto lavorando su un'applicazione legacy e sto cercando di effettuare una chiamata a una stored procedure che restituisce un intero ma sto ricevendo un errore di mappatura. L'errore stesso è questo:
Il lettore di dati non è compatibile con IF_Insert_Incidents_Citizen specificato. Un membro del tipo "intID" non ha una colonna corrispondente nel lettore di dati con lo stesso nome.
Ho provato a cambiare il nome in _intId
, sapendo che Entity Framework traduce tutti i nomi che iniziano con @variable
in una _variable
.
La cosa strana è che se utilizzo LinqPad e faccio una chiamata alla stored procedure ottengo il valore corretto di @intID
Questa è la stored procedure:
CREATE PROCEDURE [dbo].[IF_Insert_Incidents_Citizen]
@chvFolio varchar(50),
@chvOwner_Name varchar(100),
@chvOwner_Address varchar(100),
@dtsDate_Created smalldatetime,
@intUser_ID integer,
@chvDescription varchar(250),
@chvEmail varchar(50),
@intIncident_Type_ID integer,
@intIncident_Status integer,
@intID int Output
AS
SET nocount on
DECLARE @intErrorCode INT
DECLARE @intApp_ID INT
SELECT @intIncident_Type_ID = CAST(Param_Value AS INT)
FROM IF_Parameters
WHERE Param_Name = 'Citizen_Incident_Type_ID'
BEGIN
--Get an application id
INSERT INTO MasterApplication (DateCreated)
VALUES (getdate())
SELECT @intApp_ID = SCOPE_IDENTITY()
INSERT INTO IF_Incidents
(
Folio,
Owner_Name,
Owner_Address,
Date_Created,
User_ID,
Description,
Incident_Type_ID,
Incident_Status,
App_ID
)
VALUES
(
@chvFolio,
@chvOwner_Name,
@chvOwner_Address,
@dtsDate_Created,
@intUser_ID,
@chvDescription ,
@intIncident_Type_ID,
@intIncident_Status,
@intApp_ID
)
Select @intErrorCode = @@Error, @intID = SCOPE_IDENTITY()
--Insert Complaint
INSERT INTO IF_Complaints
(
Incident_ID,
Complainant_ID,
Description ,
User_ID,
Officer_Assigned_ID,
Complaint_Status_ID,
Date_Made,
Email_Complainant
)
VALUES
(
@intID,
Null,
@chvDescription + ' at ' + @chvOwner_Address,
1,
1,
1,
@dtsDate_Created ,
@chvEmail
)
Select @intErrorCode = @@Error--, @intID = SCOPE_IDENTITY()
End
Return @intErrorCode
Come puoi vedere nella stored procedure, intId ottiene sempre un valore incrementale dopo l'inserimento, chiamando SCOPE_IDENTITY()
Ora sto cercando di chiamare la mia stored procedure utilizzando Entity Framework nel seguente modo:
var bptRep = DependencyFactory.GetDependency<ICetRepository<IF_Insert_Incidents_Citizen>>();
var parameters = GetIfInsertIncidentsCitizenParamenters();
var res = bptRep.GetAllFromStoredProcedure(storedProcedure, parameters);
Il repository usa questa classe
//class with just the return value
public class IF_Insert_Incidents_Citizen
{
public int? intID { get; set; }
}
Qui ottengo tutti i parametri per la stored procedure
private IEnumerable<SqlParameter> GetIfInsertIncidentsCitizenParamenters()
{
// Create Parameters
var parameters = new List<SqlParameter>();
var param1 = CreateSqlParameter("@chvFolio", SqlDbType.NVarChar, ParameterDirection.Input, criteria["chvFolio"].Value, 50);
parameters.Add(param1);
....
var paramX = CreateSqlParameter("@intIncident_Status", SqlDbType.Int, ParameterDirection.Input, 10);
parameters.Add(paramX);
var outparam = CreateSqlParameter("@intID", SqlDbType.Int, ParameterDirection.InputOutput, DBNull.Value);
parameters.Add(outparam);
}
public IQueryable<TEntity>GetAllFromStoredProcedure(string storedProcedure, IEnumerable<SqlParameter> parameters)
{
var result = Context.Database.SqlQuery<TEntity>(storedProcedure, parameters).AsQueryable();
return result;
}
Ho seguito l'approccio suggerito da @GertArnold ma ancora non funzionante, questo sono i miei parametri e il codice
var returnCode = new SqlParameter("@ReturnCode", SqlDbType.Int);
returnCode.Direction = ParameterDirection.Output;
var sql = "exec IF_Insert_Incidents_Citizen @chvFolio, @chvOwner_Name, @chvOwner_Address, @dtsDate_Created, @intUser_ID, @chvDescription, @chvEmail, @intIncident_Type_ID, @intIncident_Status, @intID OUT";
var data = ctx.Database.SqlQuery<object>(sql, returnCode, parameters);
var result = data.FirstOrDefault();
Infine @GertArnold mi ha indirizzato nella giusta direzione, se non hai letto questo post, fallo, ti farà risparmiare un sacco di tempo. Stored procedure con parametri di output usando SqlQuery nell'API DbContext
Ho appena aggiunto al mio @intId la chiamata OUT alla chiamata exec, non è necessario creare una variabile ReturnCode e chiamare exec @ReturnCode = ....
var returnCode = new SqlParameter("@ReturnCode", SqlDbType.Int);
returnCode.Direction = ParameterDirection.Output;
Il mio codice sembra finalmente questo, per favore sii consapevole di chiamare il metodo .ToArray
sui parametri invece di passare una collezione di IEnumerable
o IList
al metodo
var sql = "exec IF_Insert_Incidents_Citizen @chvFolio, @chvOwner_Name, @chvOwner_Address, @dtsDate_Created, @intUser_ID, @chvDescription, @chvEmail, @intIncident_Type_ID, @intIncident_Status, @intID OUT";
var data = ctx.Database.SqlQuery<object>(sql, returnCode, parameters.ToArray());
var result = data.FirstOrDefault();