SqlDependency_OnChange() not firing - c#

It's the first time to use SqlDependency and i hope to find answer for my problem
The problem i'm facing is that SqlDependency_OnChange event not firing with no errors
i've enabled broker in database
ALTER DATABASE databsename SET ENABLE_BROKER;
and Changed database owner to sa
ALTER AUTHORIZATION ON databsename TO sa;
and here is my Create Table DDL
CREATE TABLE [dbo].[user_log](
[user_log_id] [bigint] NOT NULL,
[user_name] [nvarchar](100) NULL,
[action_type_id] [int] NULL,
[document_type_id] [int] NULL,
[document_id] [nvarchar](20) NULL,
[description] [nvarchar](200) NULL,
[action_date] [datetime] NULL,
[seen] [bit] NULL,
CONSTRAINT [PK_user_log] PRIMARY KEY CLUSTERED
(
[user_log_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
and wrote this code in visual studio
public User_Actions_Log_Form()
{
InitializeComponent();
try
{
SqlClientPermission SCP = new SqlClientPermission(System.Security.Permissions.PermissionState.Unrestricted);
SCP.Demand();
}
catch (Exception)
{
throw;
}
DA.DataAccess DAL = new DA.DataAccess();
SqlDependency.Stop(DAL.MyConnectionString().ConnectionString);
SqlDependency.Start(DAL.MyConnectionString().ConnectionString);
}
DataTable dt = new DataTable();
public void SearchUserLog()
{
BL.UserLogBL usr_log_bl = new BL.UserLogBL();
usr_log_bl.UserName = CBUser.SelectedValue == null ? null : CBUser.SelectedValue.ToString();
usr_log_bl.ActionTypeID = CBActionType.SelectedValue == null ? null : CBActionType.SelectedValue.ToString();
usr_log_bl.DocumentTypeID = CBDocumentType.SelectedValue == null ? null : CBDocumentType.SelectedValue.ToString();
usr_log_bl.DateFrom = DTPFrom.Checked? DTPFrom.Value.Date:(DateTime?)null;
usr_log_bl.DateTo = DTPTo.Checked ? DTPTo.Value.Date.AddSeconds(86340) : (DateTime?)null;
DA.DataAccess DAL = new DA.DataAccess();
using (SqlConnection con = new SqlConnection(DAL.MyConnectionString().ConnectionString))
{
SqlCommand cmd = new SqlCommand();
if (con.State == ConnectionState.Closed)
{
con.Open();
}
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "dbo.ManageUserLog";
SqlParameter[] para = new SqlParameter[7];
para[0] = new SqlParameter("#check", "s");
para[1] = new SqlParameter("#user_name", usr_log_bl.UserName);
para[2] = new SqlParameter("#action_type_id", usr_log_bl.ActionTypeID);
para[3] = new SqlParameter("#document_type_id", usr_log_bl.DocumentTypeID);
para[4] = new SqlParameter("#date_from", usr_log_bl.DateFrom);
para[5] = new SqlParameter("#date_to", usr_log_bl.DateTo);
para[6] = new SqlParameter("#seen", usr_log_bl.Seen);
cmd.Parameters.AddRange(para);
var depenedency = new SqlDependency(cmd);
cmd.Notification = null;
depenedency.OnChange += new OnChangeEventHandler(sqlDependency_OnChange);
dt.Rows.Clear();
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));
dataGridView1.DataSource = dt;
}
}
private void sqlDependency_OnChange(object sender, SqlNotificationEventArgs e)
{
SqlDependency SD = sender as SqlDependency;
SD.OnChange -= sqlDependency_OnChange;
if (OnNewUserActionsLogForm != null)
{
User_Actions_Log_Form_OnNewHome();
}
}
public delegate void New_User_Actions_Log_Form();
public event New_User_Actions_Log_Form OnNewUserActionsLogForm;
private void User_Actions_Log_Form_Load(object sender, EventArgs e)
{
OnNewUserActionsLogForm += new New_User_Actions_Log_Form(User_Actions_Log_Form_OnNewHome);
SearchUserLog();
}
private void User_Actions_Log_Form_OnNewHome()
{
ISynchronizeInvoke i = (ISynchronizeInvoke)this;
if (i.InvokeRequired)
{
New_User_Actions_Log_Form dd = new New_User_Actions_Log_Form(User_Actions_Log_Form_OnNewHome);
i.BeginInvoke(dd, null);
return;
}
SearchUserLog();
}
and this is the sql procedure which i called
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER proc [dbo].[ManageUserLog]
(
#user_name nvarchar(100) = null,
#action_type_id int = null,
#document_type_id int = null,
#date_from datetime = null,
#date_to datetime = null,
#seen bit = null
)
as
begin
select user_log_id,
[user_name],
dbo.GetActionTypeByID(action_type_id) as action_type,
dbo.GetDocumentTypeByID(document_type_id) as document_type,
document_id,
[description],
action_date,
seen
from dbo.user_log
where (#user_name is null or [user_name] = #user_name)
and (#action_type_id is null or action_type_id = #action_type_id)
and (#document_type_id is null or document_type_id = #document_type_id)
and (action_date between #date_from and #date_to)
and (seen = #seen)
end
so can anyone help me solving this problem

Below is a Minimal, Complete, and Verifiable example of a working Sqldependency using a simplified version of your WinForm app with hard-coded parameter values. I modified the stored procedure in your question to remove the function calls (invalid for SqlDependency notifications) and removed the #check SqlCommand parameter from the C# code since that parameter is not defined in the stored procedure.
This example works on my system so I expect it will fire the OnChange handler on your dev box when data are changed.
T-SQL setup code:
CREATE DATABASE YourDatabase;
GO
ALTER DATABASE YourDatabase SET ENABLE_BROKER;
GO
USE YourDatabase;
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[user_log](
[user_log_id] [bigint] NOT NULL,
[user_name] [nvarchar](100) NULL,
[action_type_id] [int] NULL,
[document_type_id] [int] NULL,
[document_id] [nvarchar](20) NULL,
[description] [nvarchar](200) NULL,
[action_date] [datetime] NULL,
[seen] [bit] NULL,
CONSTRAINT [PK_user_log] PRIMARY KEY CLUSTERED
(
[user_log_id] ASC
)
);
GO
INSERT INTO dbo.user_log(user_log_id, user_name, action_date, seen)
VALUES(1,'test', '2018-04-15T00:00:00', 1);
GO
CREATE proc [dbo].[ManageUserLog]
(
#user_name nvarchar(100) = null,
#action_type_id int = null,
#document_type_id int = null,
#date_from datetime = null,
#date_to datetime = null,
#seen bit = null
)
as
begin
select user_log_id,
[user_name],
--dbo.GetActionTypeByID(action_type_id) as action_type,
--dbo.GetDocumentTypeByID(document_type_id) as document_type,
document_id,
[description],
action_date,
seen
from dbo.user_log
where (#user_name is null or [user_name] = #user_name)
and (#action_type_id is null or action_type_id = #action_type_id)
and (#document_type_id is null or document_type_id = #document_type_id)
and (action_date between #date_from and #date_to)
and (seen = #seen)
end
GO
GRANT EXEC ON dbo.ManageUserLog TO public;
GO
C# WinForm code:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
static string connectionString = #"Data Source=.;Initial Catalog=YourDatabase;Integrated Security=SSPI";
public Form1()
{
InitializeComponent();
SqlDependency.Start(connectionString);
SearchUserLog();
}
public void SearchUserLog()
{
DataTable dt = new DataTable();
using (SqlConnection con = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand())
{
con.Open();
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "dbo.ManageUserLog";
SqlParameter[] para = new SqlParameter[6];
para[0] = new SqlParameter("#user_name", "test");
para[1] = new SqlParameter("#action_type_id", System.DBNull.Value);
para[2] = new SqlParameter("#document_type_id", System.DBNull.Value);
para[3] = new SqlParameter("#date_from", DateTime.Parse("2018-04-15"));
para[4] = new SqlParameter("#date_to", DateTime.Parse("2018-04-16"));
para[5] = new SqlParameter("#seen", 1);
cmd.Parameters.AddRange(para);
var depenedency = new SqlDependency(cmd);
depenedency.OnChange += new OnChangeEventHandler(sqlDependency_OnChange);
dt.Rows.Clear();
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));
}
}
private void sqlDependency_OnChange(object sender, SqlNotificationEventArgs e)
{
MessageBox.Show($"OnChange Event fired. SqlNotificationEventArgs: Info={e.Info}, Source={e.Source}, Type={e.Type}\r\n");
//resubscribe only if valid
if ((e.Info != SqlNotificationInfo.Invalid)
&& (e.Type != SqlNotificationType.Subscribe))
{
SearchUserLog();
}
}
}
}
T-SQL code to fire OnChange handler:
DECLARE #ID int = (SELECT MAX(user_log_id)+1 FROM dbo.user_log);
INSERT INTO dbo.user_log(user_log_id, user_name, action_date, seen)
VALUES(#ID,'test', '2018-04-15T00:00:00', 1);
GO

Related

SSIS C# SQLBulkCopy .csv file Error: Failed to convert parameter value from a String to a Boolean. String not recognized as a valid Boolean

I am trying to create a generic module that will load .csv files into SQL tables. The SQL tables are already created and their names, and the name of the file, will be passed as parameters. This what I have so far...
public void Main()
{
var mFilepath = Dts.Variables["InputFile"].Value.ToString();
var mSQLTable = "[Staging].[tblLoadBUF]";
Dts.Variables["StagingTableGetColumnsScript"].Value =
"IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'tblLoadBUF') " +
"BEGIN; " +
"SELECT COLUMN_NAME " +
"FROM INFORMATION_SCHEMA.COLUMNS " +
"WHERE TABLE_NAME = 'tblLoadBUF'; " +
"END; ";
string connectionString = Dts.Connections["OLEDB_CONN"].ConnectionString;
connectionString = connectionString.Trim(';');
var connStrDictionary = connectionString.Split(';').Select(x => x.Split('=')).ToDictionary(x => x[0], x => x[1]);
connectionString = "Data Source=" + connStrDictionary["Data Source"] + ";Initial Catalog=" + connStrDictionary["Initial Catalog"] + ";Integrated Security=" + connStrDictionary["Integrated Security"];
try
{
DataTable dt = new DataTable();
string contents = File.ReadAllText(mFilepath, System.Text.Encoding.GetEncoding(1252));
TextFieldParser parser = new TextFieldParser(new StringReader(contents));
parser.HasFieldsEnclosedInQuotes = true;
parser.SetDelimiters(",");
string[] fields;
while (!parser.EndOfData)
{
fields = parser.ReadFields();
if (dt.Columns.Count == 0)
{
foreach (string field in fields)
{
dt.Columns.Add(new DataColumn(string.IsNullOrWhiteSpace(field.Trim('\"')) ? null : field.Trim('\"'), typeof(string)));
}
}
else
{
dt.Rows.Add(fields.Select(item => string.IsNullOrWhiteSpace(item.Trim('\"')) ? null : item.Trim('\"')).ToArray());
}
}
parser.Close();
var columnNames = new List<string>();
using (var cn = new SqlConnection() { ConnectionString = connectionString })
{
using (var cmd = new SqlCommand() { Connection = cn })
{
cmd.CommandText = Dts.Variables["StagingTableGetColumnsScript"].Value.ToString();
cn.Open();
var reader = cmd.ExecuteReader();
while (reader.Read())
{
columnNames.Add(reader.GetString(0));
}
cn.Close();
}
}
using (SqlConnection con = new SqlConnection(connectionString))
{
using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(con))
{
sqlBulkCopy.DestinationTableName = mSQLTable;
sqlBulkCopy.ColumnMappings.Clear();
con.Open();
foreach (var column in columnNames)
{
sqlBulkCopy.ColumnMappings.Add(column.ToString(), column.ToString());
}
sqlBulkCopy.WriteToServer(dt);
con.Close();
}
}
Dts.TaskResult = (int)ScriptResults.Success;
}
catch (Exception ex)
{
Dts.Events.FireError(0, "Something went wrong ", ex.ToString(), string.Empty, 0);
Dts.TaskResult = (int)ScriptResults.Failure;
}
}
I get the following error message at execution:
System.InvalidOperationException: The given value of type String from the data source cannot be converted to type bit of the specified target column. ---> System.FormatException: Failed to convert parameter value from a String to a Boolean. ---> System.FormatException: String was not recognized as a valid Boolean.
Can somebody help me fix this ? I understand the error message, but I find it strange that it doesn't complain about decimal or integer values.
Here is my SQL Table:
CREATE TABLE [Staging].[tblLoadBUF](
[Bg_SN] [NVARCHAR](12) NOT NULL,
[Bg_Type] [NVARCHAR](7) NOT NULL,
[Bg_Expected_BUs] [NUMERIC](4, 0) NOT NULL,
[Bg_Validity_Likelihood] [DECIMAL](5, 4) NOT NULL,
[Bg_Mixed_Usage] [NUMERIC](1, 0) NOT NULL,
[Bg_Status] [NVARCHAR](1) NOT NULL,
[BU_SN] [NVARCHAR](12) NOT NULL,
[BU_Residential_Occup_Likelihood] [DECIMAL](5, 4) NOT NULL,
[BU_Last_Res_Confirmation] [DATE] NULL,
[BU_Last_NRes_Usage] [NVARCHAR](7) NULL,
[BU_Last_NRes_Confirmation] [DATE] NULL,
[BU_Validity_Likelihood] [DECIMAL](5, 4) NOT NULL,
[BU_Status] [NVARCHAR](1) NOT NULL,
[BU_Mailing_Address_Availability] [NUMERIC](1, 0) NOT NULL,
[BU_Mailing_Address_Likelihood] [DECIMAL](5, 4) NULL,
[BU_Usage] [NUMERIC](1, 0) NOT NULL,
[BU_Co_SN] [NVARCHAR](12) NULL,
[Co_Type] [NVARCHAR](5) NULL,
[Co_Validity_Likelihood] [DECIMAL](5, 4) NULL,
[Co_Status] [NVARCHAR](1) NULL,
[TN_LTotal] [INT] NOT NULL,
[TN_CTotal] [INT] NOT NULL,
[TN_OTotal] [INT] NOT NULL,
[TN_Total] [INT] NOT NULL,
[EA_Total] [INT] NOT NULL,
[BB_UID] [NUMERIC](10, 0) NULL,
[BB_BPIR] [NVARCHAR](4) NOT NULL,
[CUID] [NVARCHAR](8) NULL,
[COLB] [NVARCHAR](10) NULL,
[DAID] [NVARCHAR](8) NULL,
[DISB] [NVARCHAR](11) NULL,
[CSD_Name] [NVARCHAR](100) NULL,
[CSD_UID] [NVARCHAR](7) NULL,
[CSD_Type] [NVARCHAR](3) NULL,
[SAC_Code] [NVARCHAR](3) NULL,
[PC_CUID] [NVARCHAR](8) NULL,
[PC_DAID] [NVARCHAR](8) NULL,
[PC_CSD_UID] [NVARCHAR](7) NULL,
[PC_CSD_Type] [NVARCHAR](3) NULL,
[PC_SAC_Code] [NVARCHAR](3) NULL,
[LFS_UID] [NVARCHAR](13) NULL,
[ER_UID] [NVARCHAR](4) NULL,
[HR_UID] [NVARCHAR](4) NULL,
[PRCODE] [NVARCHAR](2) NOT NULL,
[BU_CPC_Postal_Code] [NVARCHAR](6) NULL,
[Bg_Latitude] [DECIMAL](9, 6) NULL,
[Bg_Longitude] [DECIMAL](11, 6) NULL,
[Bg_Coordinate_Type] [NVARCHAR](1) NOT NULL,
[AR_UID] [NVARCHAR](10) NULL,
[Frame_ID] [NVARCHAR](8) NULL,
[Do_Not_Contact_Flag] [BIT] NULL,
PRIMARY KEY CLUSTERED
(
[BU_SN] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
And my .csv file contains values of 1 and 0 in column [Do_Not_Contact_Flag].
Pease note that English is not my primary language, so just let me know if this is not clear enough. And thanks in advance for you help :-)
Mylene
I found the solution !!
I've modified my staging table column [Do_Not_Contact_Flag] to be SMALLINT, and added the conversion to BIT in my processing stored proc before loading in the final SQL Table.

Data not Saving in Database after Creating (CRUD)

I am working on simple CRUD application where I have two tables:
Patient
CNIC (varchar 50 and PK)
Name (varchar 50)
PatientVaccines
Cnic (varchar 50 and FK)
VaccinationName (varchar)
VaccinationDate (varchar)
CenterAddress (varchar)
I know making string as PK, FK is not a good approach but this is my requirement.
I have a PatientDBContext class where I perform CRUD operations:
public class PatentDBContext
{
string cs = ConfigurationManager.ConnectionStrings["Myconnection"].ConnectionString;
public List<Patient> getPatients()
{
List<Patient> PatientList = new List<Patient>();
SqlConnection con = new SqlConnection(cs);
string query = "SELECT p.CNIC, p.Name, pv.cnic, pv.VaccinationName, pv.VaccinationDate, pv.CenterAddress FROM Patient AS p JOIN PatientVaccines AS pv ON p.CNIC = pv.cnic";
SqlCommand cmd = new SqlCommand(query, con);
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
Patient p = new Patient();
p.CNIC = dr["CNIC"].ToString();
p.Name = dr["Name"].ToString();
p.VaccinationName = dr["VaccinationName"].ToString();
//p.VaccinationDate = dr["VaccinationDate"].ToString();
p.CentreAddress = dr["CenterAddress"].ToString();
PatientList.Add(p);
}
con.Close();
return PatientList;
}
public bool AddPatient(Patient pat)
{
SqlConnection con = new SqlConnection();
SqlCommand cmd = new SqlCommand("spAddPatient", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#CNIC", pat.CNIC);
cmd.Parameters.AddWithValue("#Name", pat.Name);
cmd.Parameters.AddWithValue("#VaccinationName", pat.VaccinationName);
cmd.Parameters.AddWithValue("#VaccinationDate", pat.VaccinationDate);
cmd.Parameters.AddWithValue("#CenterAddress", pat.CentreAddress);
con.Open();
int i = cmd.ExecuteNonQuery();
con.Close();
if (i > 0)
{
return true;
}
else
{
return false;
}
}
public bool UpdatePatient(Patient pat)
{
SqlConnection con = new SqlConnection();
string query = "UPDATE PatientVaccines SET VaccinationName = #VaccinationName, VaccinationDate = #VacinationDate, CenterAddress = #CenterAddress WHERE Cnic = #Cnic";
SqlCommand cmd = new SqlCommand(query, con);
//cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#CNIC", pat.CNIC);
//cmd.Parameters.AddWithValue("#Name", pat.Name);
cmd.Parameters.AddWithValue("#VaccinationName", pat.VaccinationName);
cmd.Parameters.AddWithValue("#VaccinationDate", pat.VaccinationDate);
cmd.Parameters.AddWithValue("#CenterAddress", pat.CentreAddress);
con.Open();
int i = cmd.ExecuteNonQuery();
con.Close();
if (i > 0)
{
return true;
}
else
{
return false;
}
}
}
Errors is this class is in getPatient() function I comment it out p.VaccinationDate that shows an error that I cannot convert implicitly type string to DateTime, how do I convert it to DateTime?
I have another function names AddPatient()that now show any error or bug but when I click submit button after input records it doesn't perform any action.
HomeController
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
PatentDBContext db = new PatentDBContext();
List<Patient> obj = db.getPatients();
return View(obj);
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Patient pat)
{
try
{
if (ModelState.IsValid == true)
{
PatentDBContext context = new PatentDBContext();
bool check = context.AddPatient(pat);
if (check == true)
{
TempData["InsertMessage"] = "Data Inserted..";
}
else
{
TempData["FailureMessage"] = "Data Not Inserted";
}
ModelState.Clear();
return RedirectToAction("Index");
}
return View();
}
catch
{
return View();
}
}
public ActionResult Edit(string Cnin)
{
PatentDBContext context = new PatentDBContext();
//string str = Cnin.ToString();
var row = context.getPatients().Find(model => model.CNIC = Cnin);
return View(row);
}
}
Here I also can't convert implicitly type string to bool
var row = context.getPatients().Find(model => model.CNIC = Cnin);
and finally this is my stored procedure:
ALTER PROCEDURE [dbo].[spAddPatient]
(#CNIC varchar(50),
#Name varchar(50),
#VaccinationName varchar(50),
#VaccinationDate varchar(50),
#CenterAddress varchar(50))
AS
BEGIN
INSERT INTO Patient (CNIC, Name)
VALUES (#CNIC, #Name)
INSERT INTO PatientVaccines (Cnic, VaccinationName, VaccinationDate, CenterAddress)
VALUES (#Cnic, #VaccinationName, #VaccinationDate, #CenterAddress)
END
I pretty sure that you are very new in this technology as there are some basic mistake. I am mentioning some common mistake below:
You should not use varchar as primary key instead use int
Make a relation in both parent and child table using int column.
Do not use varchar for date field, instead use DateTime.
I redesigned two tables as below:
Patient Table
CREATE TABLE [dbo].[Patient](
[Id] [int] IDENTITY(1,1) NOT NULL,
[CNIC] [varchar](50) NOT NULL,
[Name] [varchar](50) NOT NULL,
CONSTRAINT [PK_Patient] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
I introduce new column Id that set as IDENTITY so that this
column will get value automatically like 1, 2, 3
PatientVaccines Table
CREATE TABLE [dbo].[PatientVaccines](
[Id] [int] IDENTITY(1,1) NOT NULL,
[VaccinationName] [varchar](50) NULL,
[VaccinationDate] [datetime] NULL,
[CenterAddress] [varchar](50) NULL,
[PatientId] [int] NOT NULL,
CONSTRAINT [PK_PatientVaccines] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
I introduce two new columns Id and PatientId. when you insert a patient, the Id field will get a number automaticaly and that id will be inserted into PatientVaccines Table as PatientId so that you can find the relational data. Also I used datetime for VaccinationDate.
FOREIGN KEY CONSTRAINT
ALTER TABLE [dbo].[PatientVaccines] WITH CHECK ADD CONSTRAINT [FK_PatientVaccines_Patient] FOREIGN KEY([PatientId])
REFERENCES [dbo].[Patient] ([Id])
This is a constraint or rules that will restrict you to insert data that is not relational. for example: you do not have a record of patient with Id 101 but you are trying to insert PatientVaccines record with PatientId 101 then this rule will restrict you to do that.
Here is the Sql Diagram of Two tables
By doing the above, you need to update your Stored Procedure as below:
CREATE PROCEDURE [dbo].[spAddPatient]
(#CNIC varchar(50),
#Name varchar(50),
#VaccinationName varchar(50),
#VaccinationDate datetime,
#CenterAddress varchar(50))
AS
BEGIN
INSERT INTO Patient (CNIC, Name)
VALUES (#CNIC, #Name)
INSERT INTO PatientVaccines (PatientId, VaccinationName, VaccinationDate, CenterAddress)
VALUES (##Identity, #VaccinationName, #VaccinationDate, #CenterAddress)
END
Here is the complete C# Code where I made some correction
public class PatentDBContext
{
string cs = ConfigurationManager.ConnectionStrings["Myconnection"].ConnectionString;
public List<Patient> getPatients()
{
List<Patient> PatientList = new List<Patient>();
SqlConnection con = new SqlConnection(cs);
string query = "SELECT p.CNIC, p.Name, pv.VaccinationName, pv.VaccinationDate, pv.CenterAddress FROM Patient AS p JOIN PatientVaccines AS pv ON p.Id = pv.PatientId";
SqlCommand cmd = new SqlCommand(query, con);
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
Patient p = new Patient();
p.CNIC = dr["CNIC"].ToString();
p.Name = dr["Name"].ToString();
p.VaccinationName = dr["VaccinationName"].ToString();
p.VaccinationDate = Convert.ToDateTime(dr["VaccinationDate"]);
p.CenterAddress = dr["CenterAddress"].ToString();
PatientList.Add(p);
}
con.Close();
return PatientList;
}
public bool AddPatient(Patient pat)
{
SqlConnection con = new SqlConnection(cs);
SqlCommand cmd = new SqlCommand("spAddPatient", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#CNIC", pat.CNIC);
cmd.Parameters.AddWithValue("#Name", pat.Name);
cmd.Parameters.AddWithValue("#VaccinationName", pat.VaccinationName);
cmd.Parameters.AddWithValue("#VaccinationDate", pat.VaccinationDate);
cmd.Parameters.AddWithValue("#CenterAddress", pat.CenterAddress);
con.Open();
int i = cmd.ExecuteNonQuery();
con.Close();
if (i > 0)
{
return true;
}
else
{
return false;
}
}
public bool UpdatePatient(Patient pat)
{
SqlConnection con = new SqlConnection(cs);
string query = "UPDATE PatientVaccines SET VaccinationName = #VaccinationName, VaccinationDate = #VaccinationDate, CenterAddress = #CenterAddress WHERE PatientId = ( Select Id from Patient where Cnic = #Cnic)";
SqlCommand cmd = new SqlCommand(query, con);
cmd.Parameters.AddWithValue("#CNIC", pat.CNIC);
//cmd.Parameters.AddWithValue("#Name", pat.Name);
cmd.Parameters.AddWithValue("#VaccinationName", pat.VaccinationName);
cmd.Parameters.AddWithValue("#VaccinationDate", pat.VaccinationDate);
cmd.Parameters.AddWithValue("#CenterAddress", pat.CenterAddress);
con.Open();
int i = cmd.ExecuteNonQuery();
con.Close();
if (i > 0)
{
return true;
}
else
{
return false;
}
}
}
I believe your stored procedure is not correct, you can test it beforehand in the database.
// here you should use operator== instead of аssignment operator=
// Have in mind that .Find will throw an error if model with given Cnin is not found
var row = context.getPatients().Find(model => model.CNIC == Cnin);
How to convert a string to datetime object
Create a stored procedure
General advice, you can google the errors you get and find information about them

Store Procedure doesnt get executed. DataSet returns nothing

I have this store procedure in my db:
ALTER procedure [dbo].[AddUpdateCams]
#CamImage_UID uniqueidentifier = NULL,
#CamImage_Url1 nvarchar(50) = NULL,
#CamImage_Url2 nvarchar(50) = NULL,
#CamImage_StatusID int = 10,
#CamImage_ItemNr nvarchar(50) = NULL,
#CamImage_OrderNr nvarchar(50) = NULL
as
begin
set nocount on;
if #CamImage_UID is null
begin
set #CamImage_UID = NEWID()
insert into dbo.CamImage (CamImage_UID,CamImage_Url1, CamImage_Url2,
CamImage_StatusID, CamImage_CreateDate, CamImage_ItemNr, CamImage_OrderNr)
values (#CamImage_UID, #CamImage_Url1, #CamImage_Url2, #CamImage_StatusID,
GETDATE(), #CamImage_ItemNr, #CamImage_OrderNr)
end
else
begin
update CamImage
set CamImage_StatusID = #CamImage_StatusID
where CamImage_UID = #CamImage_UID
end
select * from CamImage where CamImage_UID = #CamImage_UID
end
I am trying to execute this store procedure by using SqlDataAdapter and DataSet, however when executed, my DataSet does not return anything and the problem doesnt seem to be in the Store Procedure because if I executed through sql studio, it doesnt run into any problems.
public DataSet runSPDataSet(string _storedProcedure)
{
DataSet _dataSet = new DataSet();
if (validateSP(_storedProcedure))
{
SqlConnection _sqlConnection = new SqlConnection(_connectionString);
SqlCommand _sqlCommand = new SqlCommand(_storedProcedure, _sqlConnection);
_sqlCommand.CommandType = CommandType.StoredProcedure;
if(_sqlParameters.Count != 0)
{
foreach (var item in _sqlParameters)
{
_sqlCommand.Parameters.Add(item.ParameterName, item.SqlDbType).Value = item.Value;
}
}
SqlDataAdapter _dataAdapter = new SqlDataAdapter(_sqlCommand);
try
{
_sqlConnection.Open();
_sqlCommand.ExecuteNonQuery();
_dataAdapter.Fill(_dataSet);
return _dataSet;
}
catch (Exception ex)
{
throw ex;
}
finally
{
_sqlConnection.Dispose();
}
}
return null;
}

I am using Visual Studio and I have a SQL Server table, but when I insert data, I get an error

I am trying to insert data into a SQL Server table, but it is not allowing me to do so and throws an error. I think the error is from the role I don't know how to fix it; please I need your help - thank you.
This is the member table that I am using:
CREATE TABLE [dbo].[Member]
(
[Member_Username] NVARCHAR (50) NOT NULL,
[Password] NVARCHAR (25) NOT NULL,
[Role] NVARCHAR (10) NULL,
[FirstName] NVARCHAR (50) NOT NULL,
[LastName] NVARCHAR (50) NOT NULL,
[Gender] NVARCHAR (8) NOT NULL,
[Email] NVARCHAR (50) NULL,
[DateOfBirth] DATE NOT NULL,
PRIMARY KEY CLUSTERED ([Member_Username] ASC)
);
And this is the error I get when inserting the values into the table:
System.Data.SqlClient.SqlException:
The parameterized query '(#memberU nvarchar(1), #pwd nvarchar(1), #role nvarchar(4000), #fna' expects the parameter '#role', which was not supplied.
This is the member class that I have for inserting the user in the database table:
public void AddMember()
{
// Open database connection
SqlConnection conn = new SqlConnection();
conn.ConnectionString = Config.GetConnectionStr();
conn.Open();
// Prepare SQL command with parameters
string sql = "INSERT INTO Member VALUES (#memberU, #pwd, #role, #fname, #lname, #gender, #email, #dob)";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("memberU", this.Member_Username);
cmd.Parameters.AddWithValue("pwd", this.Password);
cmd.Parameters.AddWithValue("role", this.Role);
cmd.Parameters.AddWithValue("fname", this.FirstName);
cmd.Parameters.AddWithValue("lname", this.LastName);
cmd.Parameters.AddWithValue("email", this.Email);
// handling null values for gender and date of birth column
if (this.Gender != null)
{
cmd.Parameters.AddWithValue("gender", this.Gender);
}
else
{
cmd.Parameters.AddWithValue("gender", DBNull.Value);
}
if (this.DateofBirth != null)
{
cmd.Parameters.AddWithValue("dob", this.DateofBirth);
}
else
{
cmd.Parameters.AddWithValue("dob", DBNull.Value);
}
// Execute command
cmd.ExecuteNonQuery();
}
And this is the sign up button:
protected void btnSignUp_Click(object sender, EventArgs e)
{
if (Page.IsValid)// assuming you have done validations using validation controls
{// c create a new object of type member and set all it's properties to values from controls
Members user = new Members();
//reading required values
user.FirstName = txtFirstName.Text;
user.LastName = txtLastName.Text;
user.Member_Username = txtUserName.Text;
user.Password = txtPassword.Text;
user.Email = txtEmail.Text;
user.Gender = rdoGender.SelectedValue;
//reading values that allow null in the database (date of birth)
if (string.IsNullOrEmpty(txtDOB.Text))
{
user.DateofBirth = null;
}
else
{
user.DateofBirth = DateTime.Parse(txtDOB.Text);
}
//call the addMember method
user.AddMember();
//redirect the user to homePage
Response.Redirect("Login.aspx");
}
}
can you try when you add parameters like ( cmd.parameters.addwithvalue("#role",value).

Adding data to database in parts (asp.net)

I have a couple of pages for booking and each page saves data. For example page one adds the destination to the database, page two is selecting amount of passengers.
I have a table to store all this:
CREATE TABLE [dbo].[Transactions] (
[cardNumber ] NCHAR (10) NULL,
[Cost] NCHAR (10) NULL,
[Passengers] NCHAR (10) NULL,
[Destination] NCHAR (10) NULL
);
On the destination page I am using the following code to input the destination to the database:
protected void Button2_Click1(object sender, EventArgs e)
{
try
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["DatabaseConnectionString"].ConnectionString);
conn.Open();
string insert = "insert into Transactions (Destination) values (#Destination)";
SqlCommand com = new SqlCommand(insert, conn);
com.Parameters.AddWithValue("#Destination", DropDownList1.SelectedItem);
com.ExecuteNonQuery();
conn.Close();
}
catch (Exception ex)
{
Response.Write("Error: " + ex.ToString());
}
Response.Redirect("Booking.aspx");
}
On the next page I have relatively the same code to enter the amount of passengers:
protected void Button2_Click(object sender, EventArgs e)
{
try
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["DatabaseConnectionString"].ConnectionString);
conn.Open();
string insert = "insert into Transactions (Passengers) values (#Passengers)";
SqlCommand com = new SqlCommand(insert, conn);
com.Parameters.AddWithValue("#Passengers", DropDownList1.SelectedItem);
com.ExecuteNonQuery();
conn.Close();
}
catch(Exception ex)
{
Response.Write("Error: " + ex.ToString());
}
Response.Redirect("Payment.aspx");
}
But after doing this no data gets entered into the database. If anyone knows of anyway that I can enter data into the database one piece at a time please let me know.
If it can’t be done this way and there is a much better way of doing this again please let me know.
Thank you all for your time.
You should have a dedicated primary key column on your table, I recommend an autoincrementing integer.
CREATE TABLE [dbo].[Transactions]
(
[ID] INT NOT NULL PRIMARY KEY IDENTITY(1,1),
[CardNumber] NCHAR (10) NULL,
[Cost] NCHAR (10) NULL,
[Passengers] NCHAR (10) NULL,
[Destination] NCHAR (10) NULL
);
Then, use stored procedures, not ad-hoc SQL.
CREATE PROCEDURE TransactionSave
(
#ID int = null,
#CardNumber nchar(10) = null,
#Cost nchar(10) = null,
#Passengers nchar(10) = null,
#Destination nchar(10) = null
)
AS
BEGIN
DECLARE #ExistingID int
SELECT #ExistingID = ID FROM Transaction WHERE ID = #ID
IF #ExistingID is null
BEGIN
--Insert
INSERT INTO Transaction (CardNumber, Cost, Passengers, Destination)
VALUES (#CardNumber, #Cost, #Passengers, #Destination)
SELECT CAST(SCOPE_IDENTITY() AS INT) AS 'TransactionID'
END
ELSE
BEGIN
--Update
UPDATE Transaction
SET
CardNumber = ISNULL(#CardNumber, CardNumber),
Cost = ISNULL(#Cost, Cost),
Passengers = ISNULL(#Passengers, Passengers),
Destination = ISNULL(#Destination, Destination),
WHERE ID = #ExistingID
SELECT #ExistingID AS 'TransactionID'
END
END
Then, in your code behind, you need to retain the ID value of the Transaction you are working on, to be sure you're updating the proper row:
protected void Button2_Click(object sender, EventArgs e)
{
int transactionID = hfID.Value;
try
{
using(SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["DatabaseConnectionString"].ConnectionString))
{
SqlCommand cmd = new SqlCommand("TransactionSave", conn);
cmd.Parameters.AddWithValue("#ID", transactionID);
cmd.Parameters.AddWithValue("#Passengers", DropDownList1.SelectedValue);
transactionID = cmd.ExecuteScalar();
hfID.Value = transactionID;
}
}
catch(Exception ex)
{
Response.Write("Error: " + ex.ToString());
}
}

Categories