New Row into SQL Server with Data Set [asp.net, c#] - c#

I have this code:
SqlConnection cnn = new SqlConnection();
cnn.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "select * from Szkoda";
cmd.Connection = cnn;
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = cmd;
DataSet ds = new DataSet();
da.Fill(ds, "Szkoda");
SqlCommandBuilder cb = new SqlCommandBuilder(da);
DataRow drow = ds.Tables["Szkoda"].NewRow();
drow["Likwidator"] = tbLikwidator.Text;
drow["FirmaObslugujaca"] = DdFirma.Text;
drow["StanSzkody"] = DdStan.Text;
drow["CzyRegres"] = DdRegres.Text;
drow["KrajZdarzenia"] = DdKraj.Text;
ds.Tables["Szkoda"].Rows.Add(drow);
da.Update(ds, "Szkoda");
The question is how to get the inserted record ID? I read about scope but I don't know how I can use this in above code.
I want to get last ID to redirect to view form after save new record.
I'm looking for simplest solution:)

You can't do that directly from the Update command of the DataAdapter. You need to prepare a custom insert command that contains two commands. The first insert your record, the second one returns the last inserted id from your connection
string insertText = #"INSERT INTO Szkoda (Likwidator,FirmaObslugujaca,
StanSzkody, CzyRegres, KrajZdarzenia)
values (#lik, #fir, #sta, #czy, #kra);
SELECT SCOPE_IDENTITY()";
SqlCommand cmd = new SqlCommand(insertText, connection);
cmd.Parameters.AddWithValue("#lik", tbLikwidator.Text);
cmd.Parameters.AddWithValue("#fir", DdFirma.Text);
cmd.Parameters.AddWithValue("#sta", DdStan.Text);
cmd.Parameters.AddWithValue("#cay", DdRegres.Text);
cmd.Parameters.AddWithValue("#kra", DdKraj.Text);
object result = cmd.ExecuteScalar();
if(result != null)
{
int lastInsertedID = Convert.ToInt32(result);
// now insert the row in your dataset table but instead of
// da.Update(ds, "Szkoda"); call
ds.Tables["Szkoda"].AcceptChanges();
}
Of course this should go alongside with your existing code, but instead of calling Update just call AcceptChanges to your datatable to confirm the new record in your table

Aftre insert the record into table(using sql query, not stored procedure) from c# code, you can use Get Records function to Select last record id(not recommended, because in muliuser case, this will be wrong) using max() fucntion.
select * from Szkoda where ID IN (select max(id) from Szkoda)
If you are using Stored Procedure to insert data, then Use SCOPE_Identity() in stored procedure, and use Output parameter to get value in c# code.
CREATE PROCEDURE dbo.testSP
#Col1 VARCHAR(50),
#Col2 VARCHAR(20),
#new_identity INT = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.TestTable(Col1, Col2) SELECT #Col1, #Col2;
SET #new_identity = SCOPE_IDENTITY();
END
GO
Refer this Return identity of last inserted row from stored procedure

Related

C# Inserting a DataSet Into SQL Database

I'm trying to insert a dataset into an SQL database but I am having difficulties passing my dataset as an argument to my DB class. I am not sure if it is allowed to pass as an argument. If not, what are my alternatives?
The way I create my dataset:
public static void getLogs() {
string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + #"\someDir";
SQLiteConnection cn = new SQLiteConnection("Data Source=" + path + ";Version=3;New=False;Compress=True;");
cn.Open();
SQLiteDataAdapter sd = new SQLiteDataAdapter("SELECT * FROM table", cn);
DataSet ds = new DataSet();
sd.Fill(ds);
cn.Close();
db.InsertLogs(Form1.adminID, Form1.deviceID, ds);
}
My database class and insert method looks like the following:
public void InsertLogs(string user_id, string device_id, DataSet history)
{
string query = "INSERT INTO table (column1, column2, column3, column4, column5, column6, column7) VALUES (#value1, #value2, #value3, #value4, #value5, #value6, #value7);";
if (OpenConnection() == true)
{
foreach (DataTable table in history.Tables)
{
foreach (DataRow row in table.Rows)
{
MySqlCommand cmd = new MySqlCommand(query, connection);
cmd.Parameters.AddWithValue("#value1", int.Parse(user_id));
cmd.Parameters.AddWithValue("#value2", int.Parse(device_id));
cmd.Parameters.AddWithValue("#value3", row[0]);
cmd.Parameters.AddWithValue("#value4", row[1]);
cmd.Parameters.AddWithValue("#value5", row[2]);
cmd.Parameters.AddWithValue("#value6", row[3]);
cmd.Parameters.AddWithValue("#value7", row[4]);
cmd.ExecuteNonQuery();
}
}
CloseConnection();
}
}
Thank you
you can loop through datatables in a dataset and can pass a datatable as a stored procedure paramater,
found an example here
1.- Go to SQL Server, under your DB name go to "programmability\Types\User-Defined Table Types, right click and create a new one:
USE DBNAME
GO
-- Create the data type
CREATE TYPE ValuesToInsert AS TABLE
(
Value1 INT NOT NULL,
Value2 INT NOT NULL,
Value3 VARCHAR(20)
)
GO
2.- Create a SP to receive the table as parameter, parameter must be the new User-Defined table type created in step 1
USE [DBNAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
--
CREATE PROCEDURE [dbo].[spImportData]
#DataImported dbo.ValuesToInsert READONLY
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
INSERT INTO [dbo].[TableName] (Value1, Value2, Value3)
SELECT Value1, Value2, Value3
FROM #DataImported
3.- Pass a datatable from your code to DB, in this case using Dapper.net as following:
DataTable dtExcelData = new DataTable();
//Fill dtExcelData and pass as parameter
ParametersCollection param = new ParametersCollection();
param.Add(CreateParameter("#DataImported", dtExcelData));
ExecuteDataSet("spImportData", CommandType.StoredProcedure, param);

MaxLength of column seems to be always -1 for the string fields in the datatable C#

All my data table column fields from the stored procedure is string fields as like given below
[Account Code] varchar(10),
Filler1 varchar(5),
[Accounting Period] varchar(7),
[Transaction Date] varchar(8),
Filler2 varchar(2),
[Record Type] varchar(1),
[Source] varchar(2),
[Journal No] varchar(5),
[Journal Line] varchar(7)
Using the below code only I am picking the value from the SP to the dataset as given below
public DataSet InvoicesToSageExtractGoodsIn(string invoiceDateFrom)
{
SqlConnection conn = null;
DALFactory dalFactory = null;
SqlDataAdapter da = null;
try
{
DataSet dsInvoiceCustomer = new DataSet();
dalFactory = new DALFactory();
conn = new SqlConnection(dalFactory.ConnectionStringVI);
conn.Open();
SqlCommand sqlCommand = new SqlCommand("prc_ReturnSageExtractGoodsIn", conn);
sqlCommand.CommandType = CommandType.StoredProcedure;
DALSystemTable dst = new DALSystemTable(this.dao);
sqlCommand.CommandTimeout = Convert.ToInt32(dst.GetSystemConstant("CommandTimeOut"));
SqlParameter param1 = sqlCommand.Parameters.Add("#InvoiceDateFrom", SqlDbType.DateTime);//VI-165
param1.Direction = ParameterDirection.Input;
param1.Value = invoiceDateFrom;
DataSet dsInvoice = new DataSet("VisionInvoicing");
DataTable dtInvoiceNos = new DataTable("tblSageExtractGoodsIn");
da = new SqlDataAdapter(sqlCommand);
da.Fill(dsInvoice);
dsInvoice.Tables[0].TableName = "tblGenerateInvoice";
return dsInvoice;
}
catch (Exception ex)
{
throw new DatabaseException(ex.Message, ex);
}
}
When I try to pick the MaxLength of the column (dtSAGEExtract.Columns[i].MaxLength) from that dataset table it always shows -1 value.
foreach (DataRow drExtract in dtSAGEExtract.Rows)
{
int fieldCount = (dtSAGEExtract.Columns.Count);
for (int i = 0; i < fieldCount; i++)
{
int length = dtSAGEExtract.Columns[i].MaxLength;
writer.Write(drExtract[i].ToString().PadRight(length));
}
writer.WriteLine();
}
writer.Close();
Does anyone have any idea why it is always showing -1 for all the fields?
First you need to add your DataTable to the DataSet to make it work after you created the DataTable because they are not connected in your example and filling the DataSource has no impact on the DataTable created in the next line so that you can use the additional schema information:
dsInvoice.Tables.Add(dtInvoiceNos);
then you need to call the SqlDataAdapter.FillSchema Method on your SqlDataAdapter to get more information from your database then just the data when using only the Fill method
da.FillSchema(dtInvoiceNos, SchemaType.Source);
da.Fill(dsInvoice);
The fill operations must be called after you added the table to the dataset.
It does not represent the MaxLength of DataTable column. It is not depend on database schema either.
It return -1 because it is default value when you do not set anything.
http://msdn.microsoft.com/en-us/library/system.data.datacolumn.maxlength(v=vs.110).aspx
Because you not fill schema to dataset.
Normaly -1 is default length of column.
You should use:
da.FillSchema(dsInvoice, SchemaType.Mapped)
UPDATE:
DataTable dtInvoiceNos = dsInvoice.Tables[0];
Please check: http://msdn.microsoft.com/en-us/library/229sz0y5(v=vs.110).aspx

asp.net C# sql query dependant on session data

I have a Session, which is list int, and I need to make a query that will take from a database only those rows that have the PK value that exists in Session.
I was thinking of doing it with the IN function, or making a new datatable with 1 collumn and values from the Session and doing a double join, probably left...
I just dont know how to make a table from a list.
What I have so far:
String ConnString = "Data Source=BRACO-PC\SQL1;Initial Catalog=DiplomskiSQL1SQL;Integrated Security=True";
SqlConnection Conn = new SqlConnection(ConnString);
Conn.Open();
DataTable ukosarici = new DataTable();
SqlDataAdapter da = new SqlDataAdapter("Select Proizvodi.ime, TipProizvoda.tip, Proizvodi.dimenzije, Proizvodi.cijena from Proizvod LEFT JOIN TipProizvoda On Proizvod.tip=TipProizvoda.id_t WHERE Proizvod.id_p IN ", Conn);
SqlCommandBuilder cmd = new SqlCommandBuilder(da);
da.Fill(ukosarici);
GridView1.DataSource = ukosarici;
GridView1.DataBind();
Conn.Close();
Create a temporary table or table variable, insert the ints into it using INSERT or BULK INSERT, do a join in the SQL query then drop the temp table or table variable.
There are many ways you could do this, but one of my preferred methods is to serialize the list to a CSV, e.g. '1,3,5,33'. I then use a custom SQL Table function to de-serialize the list and filter in the database:
SELECT * FROM mytable t
JOIN dbo.ufn_CSVtoTextList('1,3,5,33' , ',') csv
ON csv.[Entry] = t.Id
The ufn_CSVtoTextList function CREATE script is below:
CREATE FUNCTION [dbo].[ufn_CSVToTextlist] ( #StringInput nVARCHAR(max) ,#SepChar nchar(1) = ',')
RETURNS #OutputTable TABLE ( [Entry] nVarchar(255), [index] int identity (0,1) )
AS
BEGIN
DECLARE #Entry nVarChar(255)
WHILE LEN(#StringInput) > 0
BEGIN
SET #Entry = LEFT(#StringInput,
ISNULL(NULLIF(CHARINDEX(#SepChar, #StringInput) - 1, -1),
LEN(#StringInput)))
SET #StringInput = SUBSTRING(#StringInput,
ISNULL(NULLIF(CHARINDEX(#SepChar, #StringInput), 0),
LEN(#StringInput)) + 1, LEN(#StringInput))
INSERT INTO #OutputTable ( [Entry] )
VALUES ( #Entry )
END
RETURN
END
Try by changing your SqlDataAdapter Call as follows
List<int> list ; // Assign with your session int list values
List<string> l2 = list.ConvertAll<string>(delegate(int i) { return i.ToString(); });
string query = "Select Proizvodi.ime, TipProizvoda.tip, Proizvodi.dimenzije, Proizvodi.cijena from Proizvod LEFT JOIN TipProizvoda On Proizvod.tip=TipProizvoda.id_t WHERE Proizvod.id_p IN (";
query = query + string.Join(",", l2.ToArray()) + ")";
SqlDataAdapter da = new SqlDataAdapter(query, Conn);

Get affected rows on ExecuteNonQuery

I am currently working on a C# project and I am running an insert query which also does a select at the same time, e.g.:
INSERT INTO table (SELECT * FROM table WHERE column=date)
Is there a way I can see how many rows were inserted during this query?
ExecuteNonQuery - returns the number of rows affected.
SqlCommand comm;
// other codes
int numberOfRecords = comm.ExecuteNonQuery();
If you run the SQL from your question in a SqlCommand and check the return value of ExecuteNonQuery it should tell you how many records were affected.
From the documentation:
Return Value
Type: System.Int32
The number of rows affected.
Be sure of one thing also
You need to add a statement in the connection string
For example:
string const "Server=localhost; PORT=3306; Database=db; User id=root; password='';UseAffectedRows=True";
MySqlConnection con = new MySqlConnection(const);
con.Open();
MySqlCommand cmd = new MySqlCommand(con);
cmd.CommandText = "Update db set table = value where Column = value";
int numberOfRecords = cmd.ExecuteNonQuery();
Be sure of:
UseAffectedRows=True
so it will return a right value of rows affected
ExecuteNonQuery return the affected rows ONLY WHEN Use Affected Rows in the connections properties is set, if not (default) returns matched rows.
If you run a bulk of ExecuteNonQuery(), and commit them all in once, you can get the number of total changes after connection by read the return value from "SELECT total_changes();"
The function to get the total changes:
public static long GetTotalChanges(SQLiteConnection m_dbConnection)
{
string sql = "SELECT total_changes();";
using (SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection))
{
using (SQLiteDataReader reader = command.ExecuteReader())
{
reader.Read();
return (long)reader[0];
}
}
}
Use it in another function:
public static long MyBulkInserts()
{
using (SQLiteConnection m_dbConnection = new SQLiteConnection())
{
m_dbConnection.Open();
using (var cmd = new SQLiteCommand(m_dbConnection))
{
using (var transaction = m_dbConnection.BeginTransaction())
{
//loop of bulk inserts
{
cmd.ExecuteNonQuery();
}
transaction.Commit();
}
}
return GetTotalChanges(m_dbConnection);
}
}
I realize you are trying to do this with the ExecuteNonquery, but what about ExecuteScalar and using the OUTPUT directive in your query?
For Insert:
declare #resulttable
(
rowid int
)
insert yourtable
output inserted.rowid
into #resulttable
select *
from someothertable
select count(1) affectedrows
from #resulttable
or for Update, if you only want to know the rows that changed
declare #resulttable
(
beforefield1 varchar(255),
afterfield1 varchar(255)
)
update tbl1
set field1 = replace(field1, 'oldstring', 'newstring')
output deleted.field1,
inserted.field1
into #resulttable
from someothertable
select count(1) affectedrows
from #resulttable
where beforefield1 != afterfield1;

How to insert an integer value into a textbox using stored procedure calculations?

I have a stored procedure for calculating the pf of an employee as given below:
USE [test]
GO
CREATE PROCEDURE [dbo].[DA]
AS
BEGIN
SELECT e.emp_id,
e.name,
p.salary,
p.category,
p.salary * 0.12 as da
from emp as e,
payroll as p where
e.emp_id = p.emp_id
END
I have to display the result i.e values of DA in a textbox in C# when we select different values for salary from a drop down list. Please help me with the C# code.
Step 1 :
Read data in dataReader
step 2 :
Set value in textbox from the reader.
Step 3 :
In dropdwon change vent write following code....
Eample :
// Open connection to the database
string ConnectionString = "server=myserver;uid=sa;"+
"pwd=manager; database=northwind";
con = new SqlConnection(ConnectionString);
con.Open();
// Set up a command with the given query and associate
// this with the current connection.
string CommandText = "DA";
cmd = new SqlCommand(CommandText);
cmd.Connection = con;
storedProcCommand.CommandType = CommandType.StoredProcedure;
// Execute the query
rdr = cmd.ExecuteReader();
while(rdr.Read())
{
mytextbox.Text =rdr["da"].ToString() ;
}

Categories