Cannot alter table with LINQ TO SQL and stored procedure - c#

I have to alter the table Statistic when I add a new metric in the table Metric I add a column in table Statistic.
I used a stored procedure that allows me to alter the table Statistic so the code :
CREATE PROCEDURE dbo.addnewmetricInstat
(
#MetricName varchar(254),
#TypeMetric varchar(254)
)
AS
IF (#TypeMetric='int')
Begin
alter table Statistic
add #MetricName int null
end
ELSE if (#TypeMetric='string')
begin
alter table Statistic
add #MetricName varchar(254) null
end
Then I successfully called the stored procedure but the columns is not added. The code I used in C# for calling this stored procedure is:
using (DataClassesDataContext db = new DataClassesDataContext("Data Source=EMEA-TUN-WS0367\\SQLEXPRESS;Initial Catalog=Perfgas;Integrated Security=True"))
{
db.addnewmetricInstat(metric.MetricName, metric.Type);
db.SubmitChanges();
}

First you shoud not be trying to call the sp from your application until you have tested it in SSMS. That way you know if the problem is your call or the sp. It will save you much debugging time if you do this.
Your proc is the problem. You will need to use dynamic SQl for this. Right now you are trying to add a column called MetericName because you didn't use the variable. This would work once, but of course the second time you run it, you will get an error becasue teh column already exists. However you can;t just throw a variable into an alter table statement, you must use dynamic SQL.

Related

Use Stored procedures that uses the "EXECUTE" command in a TableAdapter

I am writing a program that needs to call a MSSQL stored procedure called dbo.getsystemnumber; this procedure generates the next pyd_number which I need to insert a new line in the paydetail table. This is what the procedure looks like:
ALTER PROCEDURE [dbo].[getsystemnumber](#p_controlid varchar(8), #p_alternateid varchar(8))
AS
DECLARE #return_number int
EXECUTE #return_number = dbo.getsystemnumber_gateway #p_controlid, #p_alternateid, 1
RETURN #return_number
I'm using the c# tableadapter to call this procedure but when I do call it and say put it on a label or listbox, it just returns a value of 0. The function still updates in SQL server to the next number when I run the program.
TMW_Test2DataSetTableAdapters.paydetailTableAdapter returnPydNumber = new TMW_Test2DataSetTableAdapters.paydetailTableAdapter();
lbPydnumber.Items.Add(Convert.ToInt32(returnPydNumber.getsystemnumber("PYDNUM", " ")));
However, when I use the preview data option in the tableadapter view I get the right number that I'm supposed to get. In SQL Server we call it like this:
declare #pyd_number int
execute #pyd_number = dbo.getsystemnumber N'PYDNUM', NULL
select #pyd_number
TableAdapters use the result of a SELECT statement for their data, not the RETURN value of a query. Under the hood, a single value TableAdapter will use ExecuteScalar(), which takes the first column in the first row of the resultset.
This blog post explains this and a workaround. Either change the store procedure to SELECT the value instead of RETURNing it, or change the generated code to look at the ReturnValue of the database call.

Cannot get a stored procedure table output into my .NET Application

I have a stored procedure that looks like this:
DECLARE #A TABLE ( TabYear int, Std decimal(18,2))
DECLARE #B TABLE ( TabYear int, Std decimal(18,2))
BEGIN
DECLARE #FinalTable TABLE (TabYear int, HoldayA decimal(18,2), HolidayB decimal(18,2))
BEGIN
INSERT INTO #A(TabYear, std)
Select ... from ...
INSERT INTO #B(TabYear, Std)
Select ... from ...
END
INSERT INTO #FinalTable(TabYear, HoldayA, HoldayB)
SELECT
A.TabYear, a.Std, U.Std
FROM
#A A
LEFT JOIN
#B U ON a.TabYear = U.TabYear
END
Select * from #FinalTable
Now I want to get that into a DATASET within my .NET application using the TableAdapter Wizard. I choose :"Use existing stored procedure" and choose the procedure (above) but as Data Column I get only Column1. It looks like the DataTableAdapter does not recognize the table. If I let the SP run on the server everything is fine. I get the table as I wish. I also checked if the wizard recognizes other SP's I am working with on the table and that works fine. But I have to admit that all the other SP's I use are straigth Select commands nothing with querying #Tables like in this SP. Could anyone help me get the table into my application. I do not have go go with the DataSet necessarily a code solution getting the data into an array or something would help me too.
You cannot achieve this using the TableAdapter Wizard because your stored procedure has no defined output because its dynamically created. You must manually construct the TableAdapter in your code.
Probably because you SELECT * from a table that's defined within the sproc, so the analyzer can't determine the schema. Either define the columns outside of the wizard or change your sproc to select specific columns (although the wizard won't be able to determine the type, so you'll still have to edit the data table schema).
You could also turn the sproc into one SELECT that uses subqueries instead of filling a table variable, but that may have been done for performance reasons...
I do not have go go with the DataSet necessarily
That's fine, but you'll still hove to map the columns of the result set to a structure in C# code at some point.
Wizards only take you so far; at some point you need to start casting your own spells...

Passing an array of objects to SQL stored procedure

I have 2 tables
payment (payment_id, otherCosts, GarageCosts)
spareparts (payment_id, sparepartId, sparePartQty)
In payment table payment_id is autogenerated. Apart from otherCosts and garagecosts values, in my C# asp.net application there is an array of objects with
{ sparepartId : 'Somevalue', sparePartQty : 'somevalue' }
What I need to do is in a stored procedure first enter the record into payment table with garage costs and others costs value. Then return the last generated payment ID and enter it to spareParts table as paymentId for each of the value pairs in the array.
What is the way to achieve this? Please help.
Based on your tags I am going to assume we are talking about SQL Server / T-SQL.
You could do all this in one stored procedure:
CREATE PROCEDURE dbo.Foo ... /* input parameters */
AS
BEGIN
DECLARE #PaymentId int
INSERT INTO payment(otherCosts, GarageCosts) VALUES (...)
SET #PaymentId = SCOPE_IDENTITY()
INSERT INTO spareparts(payment_id, sparepartId, sparePartQty) VALUES(#PaymentId, ...)
END
GO
You may want to also look into ##IDENTITY but make sure you read about ##IDENTITY and SCOPE_IDENTITY and understand the risks associated with the first one.
If you need to have two separate sprocs you can do that too and here is how the first sproc would look like. Note that the #PaymentId is an output parameter which means that the caller can retrieve it and pass it to the second procedure.
CREATE PROCEDURE dbo.Foo
/* input parameters */
#PaymentId int OUT
AS
BEGIN
INSERT INTO payment(otherCosts, GarageCosts) VALUES (...)
SET #PaymentId = SCOPE_IDENTITY()
END
GO
Edit - after the scope of the question was clarified:
If you need to call the second stored procedure and pass it an array of parameters, with SQL Server 2008 or newer you can use TVP (Table Value Parameters). To see how you can use them in stored procedures and how you can pass them from C# code see Table Value Parameters in SQL Server 2008 and .NET (C#) or Table-Valued Parameters.
You can also use TVPs with the solution where you only have one sproc.
To solve your problem try this
First insert your data in payment table with otherCosts and GarageCosts.
Then create a procedure to get the latest stored payment_id from payment table
create procedure select_last_payment_id
as
begin
select top 1 payment_id
from payment
order by payment_id desc
end
Lastly get that payment_id by running stored procedure and assigning it to payment_id of spareparts table and storing spareparts data.
Hope it works for you.

Insert multiple sql rows via stored proc

I have looked a some related topics but my question isn't quite answered:
C# - Inserting multiple rows using a stored procedure
Insert Update stored proc on SQL Server
Efficient Multiple SQL insertion
I have the following kind of setup when running my stored procedure in the code behind for my web application. The thing is I am now faced with the possibility of inserting multiple products and I would like to do it all in one ExecuteNonQuery rather than do a foreach loop and run it n number of times.
I am not sure how to do this, or if it can be, with my current setup.
The code should be somewhat self explanatory but if clarification is needed let me know. Thanks.
SqlDatabase database = new SqlDatabase(transMangr.ConnectionString);
DbCommand commandWrapper = StoredProcedureProvider.GetCommandWrapper(database, "proc_name", useStoredProc);
database.AddInParameter(commandWrapper, "#ProductID", DbType.Int32, entity._productID);
database.AddInParameter(commandWrapper, "#ProductDesc", DbType.String, entity._desc);
...more parameters...
Utility.ExecuteNonQuery(transMangr, commandWrapper);
Proc
ALTER PROCEDURE [dbo].[Products_Insert]
-- Add the parameters for the stored procedure here
#ProductID int,
#Link varchar(max)
#ProductDesc varchar(max)
#Date DateTime
AS BEGIN
SET NOCOUNT ON;
INSERT INTO [dbo].[Prodcuts]
(
[CategoryID],
[Link],
[Desc],
[Date]
)
VALUES
(
#ProductID,
#Link,
#ProductDesc,
#Date
)
END
You should be fine running your stored procedure in a loop. Just make sure that you commit rarely, not after every insert.
For alternatives, you have already found the discussion about loading data.
Personally, I like SQL bulk insert of the form insert into myTable (select *, literalValue from someOtherTable);
But that will probably not do in your case.
You could pass all your data as a table value parameter - MSDN has a pretty good write up about it here
Something along the lines of the following should work
CREATE TABLE dbo.tSegments
(
SegmentID BIGINT NOT NULL CONSTRAINT pkSegment PRIMARY KEY CLUSTERED,
SegCount BIGINT NOT NULL
);
CREATE TYPE dbo.SegmentTableType AS TABLE
(
SegmentID BIGINT NOT NULL
);
CREATE PROCEDURE dbo.sp_addSegments
#Segments dbo.SegmentTableType READONLY
AS
BEGIN
MERGE INTO dbo.tSegments AS tSeg
USING #Segments AS S
ON tSeg.SegmentID = S.SegmentID
WHEN MATCHED THEN UPDATE SET T.SegCount = T.SegCount + 1
WHEN NOT MATCHED THEN INSERT VALUES(tSeg.SegmentID, 1);
END
Define the commandWrapper and parameters for the command outside of the loop and then with in the loop you just assign parameter values and execute the proc.
SqlDatabase database = new SqlDatabase(transMangr.ConnectionString);
DbCommand commandWrapper = StoredProcedureProvider.GetCommandWrapper(database, "proc_name", useStoredProc);
database.AddInParameter(commandWrapper, "#ProductID", DbType.Int32 );
database.AddInParameter(commandWrapper, "#ProductDesc", DbType.String);
...more parameters...
foreach (var entity in entitties)
{
database.SetParameterValue(commandWrapper, "#ProductID",entity._productID);
database.SetParameterValue(commandWrapper, "#ProductDesc",entity._desc);
//..more parameters...
Utility.ExecuteNonQuery(transMangr, commandWrapper);
}
Not ideal from a purist way of doing things, but sometimes one is limited by frameworks and libraries, and that you are forced to call stored procedures in a certain way, bind parameters in a certain way, and that connections are managed by pools as part of your framework.
In such circumstances, a method we have found to work is to simply write your stored procedure with a lot of parameters, usually a name followed by a number, e.g. #ProductId1, #ProductDesc1, #ProductId2, #ProductDesc2 up to a number you decide, possibly say 32.
You can use some form of scripting language to produce the lines for this.
You can get the stored procedure to insert all the values first into a table parameter that allows nulls, then do bulk inserts / merges on this data in a way similar to Johnv2020's answer. You might remove the null rows first.
It will usually be more efficient than doing it one at a time (partly because of the database operations itself, and partly because of your framework's overheads in getting the connection to call the procedure etc.)

ChangeConflictException when updating rows with LINQ-to-SQL

I have a form which contains a data grid and a save button.
When the user clicks the save button I check for new rows by checking a specific column. If its value is 0 I insert the row to database, and if the column value is not 0 then I update that row.
I can insert correctly but when updating an exception occurs:
ChangeConflictException was unhandled,1 of 6 updates failed.
I have checked the update statement and I'm sure it's correct. What is the problem, can any one help me?
int id;
for (int i = 0; i < dgvInstructores.Rows.Count - 1; i++)
{
id = int.Parse(dgvInstructores.Rows[i].Cells["ID"].Value.toString());
if (id == 0)
{
dataClass.procInsertInstructores(name, nationalNum, tel1, tel2,
address, email);
dataClass.SubmitChanges();
}
else
{
dataClass.procUpdateInstructores(id, name, nationalNum, tel1, tel2,
address, email);
dataClass.SubmitChanges();
}
}
I'm using linq to query sql server2005 database and vs2008
the stored procedure for 'procUpdateInstructores' is :
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER proc [dbo].[procUpdateInstructores]
#ID int,
#name varchar(255),
#NationalNum varchar(25),
#tel1 varchar(15),
#tel2 varchar(15),
#address varchar(255),
#email varchar(255)
as
begin
BEGIN TRANSACTION
update dbo.Instructores
set
Name = #name , NationalNum = #NationalNum ,
tel1 = #tel1 , tel2 = #tel2 , address = #address , email = #email
where ID = #ID
IF (##ROWCOUNT > 0) AND (##ERROR = 0)
BEGIN
COMMIT TRANSACTION
END
ELSE
BEGIN
ROLLBACK TRANSACTION
END
end
In my experience, (working with .net forms and mvc with linq-to-sql) I have found that several times if the form collection contains the ID parameter of the data object then the update surely fails.
Even if the ID is the actual ID, it is still flagged as 'propertyChanged' when you bind it or update it or assign to another variable.
As such can we see the code for your stored procs? More specifically, the update proc?
The code you have posted above is fine, the exception should be coming from your stored proc.
However if you are confident that the proc is correct then perhaps look at the HTML code being used to generate the table. Some bugs might be present with respect to 0/1 on ID columns, etc.
In the absence of further information (what your SQL or C# update code looks like...) my first recommendation would be to do SubmitChanges once, outside the for loop, rather than submitting changes once per row.
It appears in this case that you are using a DataGridView (thus WinForms). I further guess that your dataClass is persisted on the form so that you loaded and bound the DataGridView from the same dataClass that you are trying to save the changes to in this example.
Assuming you are databinding the DataGridView to entities returned via LINQ to SQL, when you edit the values, you are marking the entity in question that it is needing to be updated when the next SubmitChanges is called.
In your update, you are calling dataClass.procUpdateInstructores(id, name, nationalNum, tel1, tel2, address, email); which immediately issues the stored procedure against the database, setting the new values as they have been edited. The next line is the kicker. Since your data context still thinks the object is still dirty, SubmitChanges tries to send another update statement to your database with the original values that it fetched as part of the Where clause (to check for concurrency). Since the stored proc updated those values, the Where clause can't find a matching value and thus returns a concurrency exception.
Your best bet in this case is to modify the LINQ to SQL model to use your stored procedures for updates and inserts rather than the runtime generated versions. Then in your parsing code, simply call SubmitChanges without calling procUpdateInstructores manually. If your dbml is configured correctly, it will call the stored proc rather than the dynamic update statement.
Also, FWIW, your stored proc doesn't seem to be doing anything more than the generated SQL would. Actually, LINQ to SQL would give you more functionality since you aren't doing any concurrency checking in your stored proc anyway. If you are required to use stored procs by your DBA or some security policy, you can retain them, but you may want to consider bypassing them if this is all your stored procs are doing and rely on the runtime generated SQL for updates.

Categories