Related
I'm running into an issue executing my connecting and inserting values into SQL Server where it's returning two different errors when using two separate models that have object references from separate classes.
The first stored procedure inserts into two separate tables. The main one has a foreign key, and the second table also has a foreign key, which has a relationship to the table coming from the second stored procedures primary key. Ultimately I am trying to find a way to execute the SQL script to pass in the values at the same time into both of these separate models.
I'm aware that I must insert first into the dbo.spUpload_Insert and then into dbo.spUploadVideo so the 'id' exists before hand. I also have verified if NULL is unchecked in my database it will insert into the appropriate tables without issue.
The first error:
Cannot insert the value NULL into column 'Video ID', table 'userMediaMetaData.dbo.Video Info Data'; column does not allow nulls. INSERT fails
The second error:
Cannot insert the value NULL into column 'ID', table 'userMediaMetaData.dbo.Basic Video Meta'; column does not allow nulls. INSERT fails
Here's the code causing the error in C# using Dapper for connecting to my database.
I'm using two different models:
public UploadInfo Upload(UploadInfo model)
{
List<String> Title = model.TitleOfVideo;
List <String> Description = model.DescriptionOfVideo;
List <String> Tags = model.Tags;
List <String> ContentId = model.Category;
int count = ContentId.Count;
string title = "";
string description = "";
string tags = "";
string contentID = "";
for (var i = 0; i < count; i++)
{
title = model.TitleOfVideo[i];
description = model.DescriptionOfVideo[i];
tags = model.Tags[i];
contentID = model.Category[i];
}
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(GlobalConfig.CnnString("userMediaMetaData")))
{
var parameters = new List<DynamicParameters>();
var p = new DynamicParameters();
p.Add("#Title", title, dbType: DbType.String, direction: ParameterDirection.Input);
p.Add("#description", description, dbType: DbType.String, direction: ParameterDirection.Input);
p.Add("#tags", tags, dbType: DbType.String, direction: ParameterDirection.Input);
p.Add("#ContentID", contentID, dbType: DbType.String, direction: ParameterDirection.Input);
p.Add("#id", 0, dbType: DbType.Int32, direction: ParameterDirection.Output);
parameters.Add(p);
connection.Execute("spUploadVideo_Insert", parameters, commandType: CommandType.StoredProcedure);
model.Id = p.Get<int>("#id");
}
return model;
throw new NotImplementedException();
}
Second model:
public ExtractionFullModel Extraction(ExtractionFullModel model)
{
string group = model.Group;
string name = model.Name;
string value = model.Value;
if (count < tot_count)
{
if (name.Contains("Directory"))
{
_directory = name;
_directory_value = value;
}
if (name.Contains("Compatible Brands"))
{
_compatbrand = name;
_compatvalue = value;
}
if (name.Contains("Time Scale"))
{
_timescale = name;
_timescale_value = value;
}
if (name.Contains("Track Duration"))
{
_duration = name;
_duration_value = value;
}
if (name.Contains("Preferred Volume"))
{
_trackvolume = name;
_trackvolume_value = value;
}
if (name.Contains("Track ID"))
{
_trackid = name;
_trackid_value = value;
}
if (name.Contains("Image Width"))
{
_imgwidth = name;
_imgwidth_value = value;
}
if (name.Contains("Image Height"))
{
_imgheight = name;
_imgheight_value = value;
}
if (name.Contains("X Resolution"))
{
_xresolution = name;
_xresolution_value = value;
}
if (name.Contains("Y Resolution"))
{
_yresolution = name;
_yresolution_value = value;
}
if (name.Contains("Video Frame Rate"))
{
_video_frame_rate = name;
_video_frame_rate_value = value;
}
if (name.Contains("Media Create Date"))
{
media_create_date = name;
media_create_date_value = value;
}
if (name.Contains("Modify Date"))
{
_modify_date = name;
_modify_date_value = value;
//modifyDate_value = DateTime.Parse(_modify_date_value);
}
if (name.Contains("Audio Format"))
{
_audioformat = name;
_audioformat_value = value;
}
if (name.Contains("Audio Channels"))
{
_audiochannels = name;
_audiochannels_value = value;
}
if (name.Contains("Audio Bits Per Sample"))
{
_audiobits = name;
_audiobits_value = value;
}
if (name.Contains("Audio Sample Rate"))
{
_audio_sample_rate = name;
_audio_sample_rate_value = value;
}
if (name.Contains("Media Data Size"))
{
_media_data_size = name;
_media_data_size_value = value;
}
if (name.Contains("Image Size"))
{
_image_size = name;
_image_size_value = value;
}
if (name.Contains("Avg Bitrate"))
{
_avg_bitrate = name;
_avg_bitrate_value = value;
}
if (name.Contains("File Size"))
{
_file_size = name;
_file_size_value = value;
}
if (name.Contains("File Modification Date/Time"))
{
_file_mod_date = name;
_file_mod_date_value = value;
//FileModifyDate_value = DateTime.Parse(_file_mod_date_value);
}
if (name.Contains("File Access Date/Time"))
{
_file_access_date = name;
_file_access_date_value = value;
//FileAccessDate_value = DateTime.Parse(_file_access_date_value);
}
if (name.Contains("File Creation Date/Time"))
{
_file_create_date = name;
_file_create_date_value = value;
//FileCreateDate_value = DateTime.Parse(_file_create_date_value);
}
if (name.Contains("File Permissions"))
{
_filepermission = name;
_filepermission_value = value;
}
if (name.Contains("File Type"))
{
_filetype = name;
_filetype_value = value;
}
if (name.Contains("MIME Type"))
{
_MIMEtype = name;
_MIMEtype_value = value;
}
if (name.Contains("Compressor ID"))
{
_compressor = name;
_compressor_value = value;
}
++count;
}
if (count >= tot_count)
{
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(GlobalConfig.CnnString("userMediaMetaData")))
{
var p = new DynamicParameters();
p.Add("#id", 0, dbType: DbType.Int32, direction: ParameterDirection.Output);
p.Add("#FileDirectory", _directory_value);
p.Add("#CompatBrand", _compatvalue);
p.Add("#TimeScale", _timescale_value);
p.Add("#Duration", _duration_value);
p.Add("#TrackVolume", _trackvolume_value);
p.Add("#TrackID", _trackid_value);
p.Add("#ImgWidth", _imgwidth_value);
p.Add("#imgHeight", _imgheight_value);
p.Add("#XResolution", _xresolution_value);
p.Add("#YResolution", _yresolution_value);
p.Add("#VideoFrameRate", _video_frame_rate_value);
p.Add("#MediaCreateDate",media_create_date_value);
p.Add("#ModifyDate", _modify_date_value);
p.Add("#AudioFormat", _audioformat_value);
p.Add("#AudioChannels", _audiochannels_value);
p.Add("#AudioBits", _audiobits_value);
p.Add("#AudioSampleRate",_audio_sample_rate_value);
p.Add("#MediaDataSize",_media_data_size_value);
p.Add("#ImageSize",_image_size_value);
p.Add("#AvgBitRate",_avg_bitrate_value);
p.Add("#FileSize",file_to_int);
p.Add("#FileModDate", _file_mod_date_value);
p.Add("#FileAccessDate", _file_access_date_value);
p.Add("#FileCreateDate", _file_create_date_value);
p.Add("#FilePermission",_filepermission_value);
p.Add("#FileType",_filetype_value);
p.Add("#MIMETYPE",_MIMEtype_value);
p.Add("#CompressorID",_compressor_value);
connection.Execute("dbo.spUpload_Insert", p, commandType: CommandType.StoredProcedure);
model.Id = p.Get<int>("#id");
}
}
return model;
}
Here's the two separate stored procedures in SQL Server.
The first stored procedure with primary key id:
ALTER PROCEDURE [dbo].[spUploadVideo_Insert]
#Title nvarchar(50),
#Description nvarchar(MAX),
#Tags nvarchar(MAX),
#ContentID int,
#id int = 0 output
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.Upload (Title, Description, Tags, [Content ID])
VALUES (#Title, #Description, #Tags, #ContentID);
SELECT #id = SCOPE_IDENTITY();
END
This is the second stored procedure inserting into two tables with the foreign keys:
ALTER PROCEDURE [dbo].[spUpload_Insert]
#FileDirectory nvarchar(50),
#CompatBrand nchar(30),
#TimeScale text,
#Duration nvarchar(15),
#TrackVolume nvarchar(15),
#TrackID nvarchar(50),
#ImgWidth text,
#imgHeight text,
#XResolution nvarchar(50),
#YResolution nvarchar(50),
#VideoFrameRate nvarchar(15),
#MediaCreateDate nvarchar(25),
#ModifyDate nvarchar(25),
#AudioFormat text,
#AudioChannels text,
#AudioBits nchar(10),
#AudioSampleRate nchar(10),
#ImageSize nchar(10),
#MediaDataSize nvarchar(10),
#AvgBitRate nvarchar(50),
#FileSize nvarchar(10),
#FileModDate nvarchar(25),
#FileAccessDate nvarchar(25),
#FileCreateDate nvarchar(25),
#FilePermission nvarchar(50),
#FileType nvarchar(15),
#MIMEType nvarchar(20),
#CompressorID nvarchar(20),
#id int = 0 output
AS
BEGIN
SET NOCOUNT ON;
-- Adding video extraction information
INSERT INTO dbo.[Video Info Data]([File Directory], [Compatible Brands], [Time Scale], [Duration], [Track Volume], [Track ID], [Img Width], [Img Height],
[X Resolution], [Y Resolution], [Video Frame Rate], [Media Create Date], [Modify Date], [Audio Format], [Audio Channels],
[Audio Bits], [Audio Sample Rate], [Media Data Size], [Image Size], [Average Bit Rate], [MIME Type], [Compressor ID])
VALUES (#FileDirectory, #CompatBrand, #TimeScale, #Duration, #TrackVolume, #TrackID, #ImgWidth, #imgHeight, #XResolution, #YResolution, #VideoFrameRate, #MediaCreateDate, #ModifyDate,
#AudioFormat, #AudioChannels, #AudioBits, #AudioSampleRate, #MediaDataSize, #ImageSize, #AvgBitRate, #MIMEType, #CompressorID);
--Adding video extract DATE information
insert into dbo.[Basic Video Meta]([File Directory],[File Size],[File Type],
[File Mod Date],[File Access Date],[File Create Date],[File Permission])
values(#FileDirectory,#FileSize,#FileType,#FileModDate,#FileAccessDate,#FileCreateDate,#FilePermission);
select #id = SCOPE_IDENTITY();
END
So far I have tried moving the method for 'Upload' before the 'Extraction" method thinking that maybe if I insert into the Extraction method first the 'id' would be set and then I wouldn't run into issues once I tried to insert into the database. This just gave me the same "column does not allow nulls" error. I also tried changing how my variables are passed into the methods by changing at what point the 'id' parameter was inserted into the database, this still presented the same result.
Do I need to use some sort of casting, or transaction? and if so do I use this within Dapper and my C# class, or do I need to do this within the stored procedure of my database?
I have different input parameters to enter and all those parameters need to enter in different tables. Therefore I use 3 different stored procedures. From each stored procedure, i need to use the output parameter of the former stored procedure as an input parameter.
Those are the 3 stored procedures that I use
Stored procedure 1 = Levlotnr:
create procedure Levlotnr
(#lotleverancier nvarchar (256),
#leverancier nvarchar (256),
#newinsertedlevID int output)
as
insert into leveranciersLotnr
values (#lotleverancier,
(select leveranciersID
from Leverancier
where LeveranciersNaam = #leverancier) )
select ##IDENTITY as newinsertedlevID
Stored procedure 2 = LotIN:
create procedure LotIN
(#datumIN datetime,
#hoeveelIN decimal,
#grondstofIN nvarchar(256),
#newinsertedLotnrINID int output,
#lotnlevID int)
as
insert into LotnummerIN
values (#datumIN, #hoeveelIN,
(select GrondstofID
from Grondstoffen
where Grondstofomschrijving = #grondstofIN),
#lotnlevID)
select ##IDENTITY as newinsertedLotnrIN
Stored procedure 3 = StockIN:
create procedure StockIN
(#omschrstockIN nvarchar (256),
#lotnrIN int)
as
update StockPlaatsIN
set LotnummerINID = #lotnrIN
where StockINOmschrijving = #omschrstockIN
And this is a code that I already wrote
public void Nieuweontvangst (DateTime datumIN, string leverancier,
string levlotnr, double hoeveelheidIN,
string eenheidIN, string grondstofIN,
string stockplaatsIN, int lotnrlevID, int lotnrINID)
{
var manager = new LotnummersDBManager();
using (var conLotnummers = manager.Getconnection())
{
conLotnummers.Open();
using (var traNieuweOntvangst =
conLotnummers.BeginTransaction(IsolationLevel.ReadCommitted))
{//begin traNieuweOntvangst
//first transaction: the output parameter #newinsertedlevID
//just needs to be used in the second transaction, but not be displayed
//------------------
using (var comlevlotnrs = conLotnummers.CreateCommand())
{
comlevlotnrs.Transaction = traNieuweOntvangst;
comlevlotnrs.CommandType = CommandType.StoredProcedure;
comlevlotnrs.CommandText = "Levlotnr"; //name of first
stored procedure
var parlotleverancier = comlevlotnrs.CreateParameter();
parlotleverancier.ParameterName = "#Lotleverancier";
parlotleverancier.Value = levlotnr;
comlevlotnrs.Parameters.Add(parlotleverancier);
var parleverancier = comlevlotnrs.CreateParameter();
parleverancier.ParameterName = "#leverancier";
parleverancier.Value = leverancier;
comlevlotnrs.Parameters.Add(parleverancier);
var parlotlevID = comlevlotnrs.CreateParameter();
parlotlevID.ParameterName = "#newinsertedlevID";
parlotlevID.DbType = DbType.Int32;
parlotlevID.Direction = ParameterDirection.Output;
comlevlotnrs.Parameters.Add(parlotlevID);
}
using (var comLotnrsIN = conLotnummers.CreateCommand())
{// second transaction= output parameter #newinsertedlevID
// should be used here where now stands #lotnrlevIN.
// THIS IS WHERE I STRUGGLE
// also here I get an output parameter
// #newinsertedLotnrINID only to be used in the 3rd
// transaction, not to be displayed.
comLotnrsIN.Transaction = traNieuweOntvangst;
comLotnrsIN.CommandType = CommandType.StoredProcedure;
comLotnrsIN.CommandText = "LotnrIN";
var pardatumIN = comLotnrsIN.CreateParameter();
pardatumIN.ParameterName = "#datumIN";
pardatumIN.Value = datumIN;
comLotnrsIN.Parameters.Add(pardatumIN);
var parhoeveelIN = comLotnrsIN.CreateParameter();
parhoeveelIN.ParameterName = "#hoeveelIN";
parhoeveelIN.Value = hoeveelheidIN;
comLotnrsIN.Parameters.Add(parhoeveelIN);
var pargrondstofIN = comLotnrsIN.CreateParameter();
pargrondstofIN.ParameterName = "#grondstofIN";
pargrondstofIN.Value = grondstofIN;
comLotnrsIN.Parameters.Add(pargrondstofIN);
var parlotnrlevIN = comLotnrsIN.CreateParameter();
parlotnrlevIN.ParameterName = "#lotnrlevIN";
parlotnrlevIN.Value = lotnrlevID;
comLotnrsIN.Parameters.Add(parlotnrlevIN);
var parLotIN = comLotnrsIN.CreateParameter();
parLotIN.ParameterName = "#newinsertedLotnrINID";
parLotIN.DbType = DbType.Int32;
parLotIN.Direction = ParameterDirection.Output;
comLotnrsIN.Parameters.Add(parLotIN);
}
using (var comStockeren = conLotnummers.CreateCommand())
{
//Third transaction
// I need to use the output parameter from 2nd transaction
// #newinsertedLotnrINID where you see now #lotnrINID.
//THIS IS THE SAME STRUGGLE AS 2ND TRANSACTION
comStockeren.Transaction = traNieuweOntvangst;
comStockeren.CommandType = CommandType.StoredProcedure;
comStockeren.CommandText = "StockIN";
var parlotIN = comStockeren.CreateParameter();
parlotIN.ParameterName = "#lotnrINID";
parlotIN.Value = lotnrINID;
var paromschrStockIN = comStockeren.CreateParameter();
paromschrStockIN.ParameterName = "#omschrstockIN";
paromschrStockIN.Value = stockplaatsIN;
comStockeren.Parameters.Add(paromschrStockIN);
}
traNieuweOntvangst.Commit();
}
}
}
Procedure (modified):
alter procedure searchProgramUnitResult(
#id char(10)
)
as
begin
select id from table1 where id = #id
end
Sam procedure in the DBML Designer (after importing the procedure to the MVC project):
[global::System.Data.Linq.Mapping.FunctionAttribute(Name="dbo.searchProgramUnit")]
public ISingleResult<searchProgramUnitResult> searchProgramUnit([global::System.Data.Linq.Mapping.ParameterAttribute(DbType="VarChar(10)")] ref string id){
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())),id);
id = ((string)(result.GetParameterValue(0)));
return ((ISingleResult<searchProgramUnitResult>)(result.ReturnValue));
}
Question is, how do I retrieve the result set in another C# class?
public ??Data-type search (string id){
DataContextClass db = new DataContextClass();
??Datatype results = db.searchProgramUnit(id);
return results;
}
If you have mapped the stored procedure in your DbContext you can call it like that:
using (var context = new DataContextClass())
{
var courses = context.searchProgramUnit("1");
foreach (table1 cs in table1s)
Console.WriteLine(cs.Name);
}
another approach which works also with Code First:
using (var ctx = new DataContextClass())
{
var idParam = new SqlParameter
{
ParameterName = "id",
Value = "1"
};
var table1List = ctx.Database.SqlQuery<table1>("exec searchProgramUnitResult #id ", idParam).ToList<table1>();
foreach (table cs in table1List)
Console.WriteLine("Name: {0}", cs.Name);
}
table1 is your entity/class name!
Are you asking about the data type?
public List<string> search (string id){
DataContextClass db = new DataContextClass();
List<string> results = db.searchProgramUnit(id).ToList();
return results;
}
I am new to entity framework. I have a procedure which save shipment data and I have to convert that procedure into entity framework function. For simple insert/update I am able to use entity framework but for this particular procedure I am facing issue.
In below procedure I have to update shipment table which have addressId, shipmenStatusId and serviceId as a foreign key. For particular shipment record if address is already exists then add existing address id in foreign key column otherwise first add new address into address table and then pick newly address id and update it into shipment address id column and same step for shipmentStatusType and service type.
Here is my procedure script.
CREATE PROCEDURE spSavePackage
#TrackingNbr VARCHAR(50),
#Carrier VARCHAR(10),
#PackageType VARCHAR(20) = NULL,
#ShippedDate DATETIME = NULL,
#ScheduledDate DATETIME = NULL,
#AddressLine1 VARCHAR(50)= NULL,
#AddressLine2 VARCHAR(50)= NULL,
#City VARCHAR(50) = NULL,
#State VARCHAR(2) = NULL,
#Country VARCHAR(2) = NULL,
#StatusDescription VARCHAR(50) = NULL
AS
BEGIN
DECLARE #AddressId int, #DeliveryStatusId int , #PackageId int
IF EXISTS (SELECT Id FROM tblPackages WHERE TrackingNr = #TrackingNbr AND Carrier = #Carrier)
BEGIN
IF EXISTS(SELECT Id FROM tblDeliveryAddress WHERE Address1 = #AddressLine1 AND Address2 = #AddressLine2
AND City = #City AND State = #State AND Country = #Country)
BEGIN
SELECT #AddressId = Id FROM tblDeliveryAddress WHERE Address1 = #AddressLine1 AND Address2 = #AddressLine2
AND City = #City AND State = #State AND Country = #Country
END
ELSE
BEGIN
SELECT #AddressId = MAX(Id) from tblDeliveryAddress
SET #AddressId = #AddressId + 1
INSERT INTO tblDeliveryAddress VALUES(#AddressId , #AddressLine1 , #AddressLine2 , #City , #State , #Country)
END
IF EXISTS (SELECT Id FROM tblDeliveryStatus WHERE Status = #StatusDescription)
BEGIN
SELECT #DeliveryStatusId = Id FROM tblDeliveryStatus WHERE Status = #StatusDescription
END
ELSE
BEGIN
SELECT #DeliveryStatusId = MAX(Id) FROM tblDeliveryStatus
SET #DeliveryStatusId = #DeliveryStatusId + 1
INSERT INTO tblDeliveryStatus VALUES(#DeliveryStatusId , #StatusDescription)
END
UPDATE tblPackages
SET DeliveryAddressID = #AddressId, DeliveryStatusId = #DeliveryStatusId,
ShippedDate = #ShippedDate , PackageType = #PackageType, ScheduledDate = #ScheduledDate
WHERE TrackingNr = #TrackingNbr AND Carrier = #Carrier
END
ELSE
BEGIN
SELECT #PackageId = MAX(Id) FROM tblPackages
SET #PackageId = #PackageId + 1
INSERT INTO tblPackages(Id , TrackingNr , Carrier) VALUES (#PackageId , #TrackingNbr , #Carrier)
END
END
For implementing functionality of this procedure I had created written following EF code.
public void UpdateShipments(List<Tuple<tblShipment, List<tblActivity>>> shipments)
{
tblShipment shipment = null;
var manager = ((IObjectContextAdapter)this._context).ObjectContext.ObjectStateManager;
foreach (var tuple in shipments)
{
shipment = tuple.Item1;
if (shipment.ConsigneeAddress != null)
{
shipment.ConsigneeAddressId = this.AddAddress(shipment.ConsigneeAddress).ID;
shipment.ConsigneeAddress = null;
}
else
{
shipment.ConsigneeAddressId = null;
shipment.ConsigneeAddress = null;
}
if (shipment.ShipperAddress != null)
{
shipment.ShipperAddressId = this.AddAddress(shipment.ShipperAddress).ID;
shipment.ShipperAddress = null;
}
else
{
shipment.ShipperAddressId = null;
shipment.ShipperAddress = null;
}
if (shipment.Service != null)
{
shipment.ServiceId = this.AddService(shipment.Service).ID;
shipment.Service = null;
}
else
{
shipment.ServiceId = null;
shipment.Service = null;
}
if (shipment.ShipmentStatusType != null)
{
shipment.ShipmentStatusId = this.AddStatusType(shipment.ShipmentStatusType).ID;
shipment.ShipmentStatusType = null;
}
else
{
shipment.ShipmentStatusId = null;
shipment.ShipmentStatusType = null;
}
this._context.Entry(shipment).State = System.Data.Entity.EntityState.Modified;
}
this._context.SaveChanges();
}
public tblAddressType AddAddressType(tblAddressType addressType)
{
tblAddressType tempAddressType = (from m in this._context.AddressTypes
where m.Type.ToUpper() == addressType.Type.ToUpper()
select m).FirstOrDefault();
if (tempAddressType == null)
{
tempAddressType = this._context.AddressTypes.Add(addressType);
this._context.SaveChanges();
}
return tempAddressType;
}
public tblAddress AddAddress(tblAddress address)
{
tblAddress tempAddress = (from m in this._context.Addresses
where m.AddressLine1.ToUpper() == address.AddressLine1.ToUpper() && m.AddressLine2.ToUpper() == address.AddressLine2.ToUpper() && m.City.ToUpper() == address.City.ToUpper()
&& m.StateProvinceCode.ToUpper() == address.StateProvinceCode.ToUpper() && m.CountryCode.ToUpper() == address.CountryCode.ToUpper()
select m).FirstOrDefault();
if (tempAddress == null)
{
address.AddressType = this.AddAddressType(address.AddressType);
address.AddressTypeId = address.AddressType.ID;
address.AddressType = null;
tempAddress = this._context.Addresses.Add(address);
this._context.SaveChanges();
}
return tempAddress;
}
After spending lots of time I found this way to implement it but I am not satisfied with this implementation. As I have to do lot's of hit for saving/updating shipment records which slowing the process. I need some optimized way to update shipment records so that for saving records I have to do only single database hit. I have multiple shipments record(records which is in collection) and I want single database hit to save records or 1 database hit to save one shipment records.
I tried to clarify my problems if any one facing issue to understand it then let me know. I am using c# as a programming language, sql server as a database and entity framework 6.0 as ORM.
Any help would be appreciated.
Thanks,
Awadhendra
I've had a similar problem in the past.
While it probably would be considered a hack by some others due to the nature of hard coding things that may change, if you also implement even simple integration tests (see later for an example) it is possible to keep track of such changes
Here is my solution
namespace ContextNamespace
{
public partial class ContextClass
{
public Task UpdateShipments(List<Tuple<tblShipment,
List<tblActivity>>> shipments)
{
return this.Database.ExecuteSqlCommandAsync("EXEC spSavePackage #p1 = #p1..",
new SqlParameter("#p1", shipments.???),....);
}
}
}
Along side this I have integration tests like this one, that their purpose is only to pass without exceptions -of course they can easily be fleshed out to include more proper checks
[TestMethod]
public async Task Sproc_Test()
{
//Create object
Context context = new Context();
await context.UpdateShipments(/*object*/);
}
An example of use in code is like this
public Task DoSomething(Object data)
{
return Context.UpdateShipments(data);
}
My problem is that when i run C# method that fires firebird stored procedure, it adds more that one row, mostly it's 2, but 3 or more happend. I want only one row to be added per use of this code.
When i run SP manually from firebird everything is ok. It seems that C# code causes problem somwehere but i have no idea where.
During debugging rows are inserted ofcourse after I pass ft.Commit();
I hope i made it clear, if not the please ask, i'll try to explain better. Sorry if code is not right formatted, i'm writing first time here.
Here is C# method:
public int AddKursowka(string nrLinii, int typLinii, string kodLinii, string nazwaKwi, string txtKwi, DateTime dateStart, DateTime dateStop,
int idLinii,int idKursowki, int idTxtKursowka)
{
FbTransaction ft = null;
int _result = -1;
try
{
Connect();
{
ft = mFbConn.BeginTransaction();
using (FbCommand com = new FbCommand(
"EXECUTE PROCEDURE ADD_KURSOWKA(#NRLINII, #TYPLINII, #KODLINII, #NAZWAKWI, #TXTKWI, #DATASTART, #DATASTOP, " +
"#IDLINII, #IDKURSOWKI, #IDTXTKURSOWKA, #PRJ);", mFbConn, ft))
{
com.CommandType = CommandType.StoredProcedure;
com.Parameters.Add("#NRLINII", FbDbType.VarChar, 100).Value = nrLinii;
com.Parameters.Add("#TYPLINII", FbDbType.BigInt).Value = typLinii;
com.Parameters.Add("#KODLINII", FbDbType.VarChar, 50).Value = kodLinii;
com.Parameters.Add("#NAZWAKWI", FbDbType.VarChar, 10).Value = nazwaKwi;
com.Parameters.Add("#TXTKWI", FbDbType.VarChar, 12).Value = txtKwi;
com.Parameters.Add("#DATASTART", FbDbType.Date).Value = dateStart;//.Date;
com.Parameters.Add("#DATASTOP", FbDbType.Date).Value = dateStop;//.Date;
com.Parameters.Add("#IDLINII", FbDbType.BigInt).Value = idLinii;
com.Parameters.Add("#IDKURSOWKI", FbDbType.BigInt).Value = idKursowki;
com.Parameters.Add("#IDTXTKURSOWKA", FbDbType.BigInt).Value = idTxtKursowka;
com.Parameters.Add("#PRJ", FbDbType.VarChar, 100).Value = Variables.Instance.LastPRJ;
// 1-3 - update / 4-6 - insert
com.ExecuteScalar();// _result = (int)
}
ft.Commit();
}
Disconect();
}
catch (Exception ex) { Functionalities.WriteLog(ex); ft.Rollback(); }
finally
{
if (ft != null) ft.Dispose();
}
return _result;
}
And here is procedure:
ALTER PROCEDURE ADD_KURSOWKA (
NRLINII Varchar(100),
TYPLINII Bigint,
KODLINII Varchar(50),
NAZWAKWI Varchar(10),
TXTKWI Varchar(12),
DATASTART Date,
DATASTOP Date,
IDLINII Bigint,
IDKURSOWKI Bigint,
IDTXTKURSOWKA Bigint,
PRJ Varchar(100) )
RETURNS (
RESULT Integer )
AS
DECLARE VARIABLE idKursowka BIGINT;
DECLARE VARIABLE aResult INTEGER;
DECLARE VARIABLE bResult INTEGER;
DECLARE VARIABLE txtRes BIGINT;
DECLARE VARIABLE lineRes BIGINT;
BEGIN
if(:IDKURSOWKI = -1)
then
begin
INSERT INTO KURSOWKA (TYPDNIA, KODLINII, NRBRYGADY, LICZBAKURSOW, NAZWAKWI,
NRZAJEZDNI, REZERWA, WYKLUCZENIADNIATYGODNIA, WYKLUCZENIAOKRESOWE, IDPRZEWOZNIKA,
PRJ_NAME)
VALUES(1, :KODLINII, 1, 0, :NAZWAKWI, 0, 0, 0, 0, 0, :PRJ);
idKursowka = (select max(k.IDKURSOWKA) from KURSOWKA k where k.PRJ_NAME = :PRJ);
bResult = 4;
execute procedure ADD_TXT_KURSOWKA
:IDTXTKURSOWKA, :TXTKWI, :idKursowka, :DATASTART, :DATASTOP, :PRJ
returning_values :txtRes;
RESULT = RESULT + txtRes;
execute procedure ADD_LINE_V2
:IDLINII, :NRLINII, :TYPLINII, :PRJ, :KODLINII
returning_values :lineRes;
RESULT = RESULT + lineRes;
end
else
begin
UPDATE KURSOWKA k SET k.KODLINII = :KODLINII, k.NAZWAKWI = :NAZWAKWI
WHERE k.IDKURSOWKA = :IDKURSOWKI and k.PRJ_NAME = :PRJ;
idKursowka = :IDKURSOWKI;
aResult = 1;
execute procedure ADD_TXT_KURSOWKA
:IDTXTKURSOWKA, :TXTKWI, :idKursowka, :DATASTART, :DATASTOP, :PRJ
returning_values :txtRes;
RESULT = RESULT + txtRes;
execute procedure ADD_LINE_V2
:IDLINII, :NRLINII, :TYPLINII, :PRJ, :KODLINII
returning_values :lineRes;
RESULT = RESULT + lineRes;
end
END
ALTER PROCEDURE ADD_LINE_V2 (
IDLINII Bigint,
NRLINII Varchar(100),
TYPLINII Bigint,
PRJ_NAME Varchar(100),
KOD_LINII Varchar(50) )
RETURNS (
RESULT Integer )
AS
BEGIN
if(:IDLINII = -1)
then
begin
INSERT INTO LINIE(NRLINII, TYPLINII, PRJ_NAME, KOD_LINII)
VALUES(:NRLINII, :TYPLINII, :PRJ_NAME, :KOD_LINII);
RESULT = 1;
end
else
begin
update LINIE l set l.KOD_LINII = :KOD_LINII,
l.NRLINII = :NRLINII, l.TYPLINII = :TYPLINII
where l.PRJ_NAME = :PRJ_NAME and l.IDLINII = :IDLINII;
RESULT = 2;
end
END
ALTER PROCEDURE ADD_TXT_KURSOWKA (
IDTXTKURSOWKA Bigint,
TXTKWI Varchar(12),
IDKURSOWKA Bigint,
DATASTART Date,
DATASTOP Date,
PRJ Varchar(100) )
RETURNS (
RESULT Integer )
AS
BEGIN
if(:IDTXTKURSOWKA = -1)
then
begin
INSERT INTO TXT_KURSOWKA(TXTKWI, WSKKURSOWKI, DATAPSTART,
DATAPSTOP, PRJ_NAME)
VALUES(:TXTKWI, :idKursowka, :DATASTART, :DATASTOP, :PRJ);
RESULT = 1;
end
else
begin
update TXT_KURSOWKA txt set txt.DATAPSTART = :DATASTART,
txt.DATAPSTOP = :DATASTOP,
txt.TXTKWI = :TXTKWI, txt.WSKKURSOWKI = :idKursowka
where txt.ID_TXT_KURSOWKA = :idKursowka;
RESULT = 2;
end
END
Ok. It turns out i have made mistakes in stored procedures and I found that by manually adding more rows and somehow i found where values didnt match to which i gave as parameters. C# code is fine i guess. As far as i'm checking now it runs fine.
This is proper code. Two sub procedures had mistakes:
SET TERM ^ ;
ALTER PROCEDURE ADD_TXT_KURSOWKA (
IDTXTKURSOWKA Bigint,
TXTKWI Varchar(12),
IDKURSOWKA Bigint,
DATASTART Date,
DATASTOP Date,
PRJ Varchar(100) )
RETURNS (
RESULT Integer )
AS
BEGIN
if(IDTXTKURSOWKA = -1)
then
begin
INSERT INTO TXT_KURSOWKA(TXTKWI, WSKKURSOWKI, DATAPSTART,
DATAPSTOP, PRJ_NAME)
VALUES(:TXTKWI, :IDKURSOWKA, :DATASTART, :DATASTOP, :PRJ);
RESULT = 1;
end
else
begin
update TXT_KURSOWKA txt set txt.DATAPSTART = :DATASTART,
txt.DATAPSTOP = :DATASTOP,
txt.TXTKWI = :TXTKWI, txt.WSKKURSOWKI = :IDKURSOWKA
where txt.ID_TXT_KURSOWKA = :IDTXTKURSOWKA;
RESULT = 2;
end
ALTER PROCEDURE ADD_LINE_V2 (
IDLINII Bigint,
NRLINII Varchar(100),
TYPLINII Bigint,
PRJ_NAME Varchar(100),
KOD_LINII Varchar(50)
)
RETURNS
(
RESULT Integer
)
AS
BEGIN
if(IDLINII = -1)
then
begin
INSERT INTO LINIE(NRLINII, TYPLINII, PRJ_NAME, KOD_LINII)
VALUES(:NRLINII, :TYPLINII, :PRJ_NAME, :KOD_LINII);
RESULT = 1;
end
else
begin
update LINIE l set l.KOD_LINII = :KOD_LINII,
l.NRLINII = :NRLINII, l.TYPLINII = :TYPLINII
where l.PRJ_NAME = :PRJ_NAME and l.IDLINII = :IDLINII;
RESULT = 2;
end
END