I'm writing a project in C# where i use ADO.NET to connect to my SQL Server 2012 database. My database (among other things ) has two columns. the first column represent latitude of a point and the second one represents the longitude. I use a procedure that check if two rectangles on the map intercept each the other. The column reply returns 1 value that is either 0 or 1.
edit: in this example i run it only with numbers, i plan to add variables later
my procedure works fine if i run it on SQL query. But drops error if i run using ADO.net
as SQL query procedure is :
DECLARE #g geography;
DECLARE #h geography;
DECLARE #s geography;
SET #g = geography::STGeomFromText('POLYGON((39.692 23.483, 23.483 39.671, 24.095 39.493, 23.466 39.800,39.692 23.483))', 4326);
SET #h = geography::STGeomFromText('POLYGON((39.800096 23.296509, 39.628961 23.128967,39.43195 23.510742 ,39.7093 23.859558,39.800096 23.296509))', 4326);
SET #h =#h.MakeValid();
SET #g = #g.MakeValid();
SELECT #g.STIntersects(#h) as reply
/*==============================================================================================================
//------------------------ AS ADO.NET procedure is : -------------------------------
SqlDataReader rdr = null;
SqlConnection conn = new SqlConnection("Data Source=AGIS-PC;Initial Catalog=ship_maps;Integrated Security=True");// create a connection object
String commandString = #"DECLARE #g geography;
DECLARE #h geography;
DECLARE #s geography;
SET #h =#h.MakeValid();
SET #g = #g.MakeValid();
SET #g = geography::STGeomFromText('POLYGON((39.692 23.483, 23.483 39.671, 24.095 39.493, 23.466 39.800,39.692 23.483))', 4326);
SET #h = geography::STGeomFromText('POLYGON((39.800096 23.296509, 39.628961 23.128967,39.43195 23.510742 ,39.7093 23.859558,39.800096 23.296509))', 4326);
SET #h =#h.MakeValid();
SET #g = #g.MakeValid();
SELECT #g.STIntersects(#h) as reply";
SqlCommand cmd = new SqlCommand(commandString, conn);
try
{
// open the connection
conn.Open();
// 1. get an instance of the SqlDataReader
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
// get the results of each column
string vessel_name = (string)rdr["reply"];
TextBox1.Text += " " + vessel_name;
// .....
}//while
}
finally
{
//...........
}
//=========================================================
he error is something with makevalid() i guess. I had similar error in the initial query at sql , then i insert makevalid() and it worked.
edit : it occurs at rdr = cmd.ExecuteReader();
Stack Trace:
[SqlException (0x80131904): A .NET Framework error occurred during execution of user-defined routine or aggregate "geography":
System.ArgumentException: 24200: The specified input does not represent a valid geography instance. Use MakeValid to convert the instance to a valid instance. Note that MakeValid may cause the points of a spatial instance to shift slightly.
System.ArgumentException:
at Microsoft.SqlServer.Types.SqlGeography..ctor(GeoData g, Int32 srid)
at Microsoft.SqlServer.Types.SqlGeography.GeographyFromText(OpenGisType type, SqlChars taggedText, Int32 srid)
.
A .NET Framework error occurred during execution of user-defined routine or aggregate "geography":
Microsoft.SqlServer.Types.GLArgumentException: 24205: The specified input does not represent a valid geography instance because it exceeds a single hemisphere. Each geography instance must fit inside a single hemisphere. A common reason for this error is that a polygon has the wrong ring orientation. To create a larger than hemisphere geography instance, upgrade the version of SQL Server and change the database compatibility level to at least 110.
Microsoft.SqlServer.Types.GLArgumentException:
at Microsoft.SqlServer.Types.GLNativeMethods.GeodeticIsValid(GeoData& g, Double eccentricity, Boolean forceKatmai)
at Microsoft.SqlServer.Types.SqlGeography.IsValidExpensive(Boolean forceKatmai)
at Microsoft.SqlServer.Types.SqlGeography..ctor(GeoData g, Int32 srid)
at Microsoft.SqlServer.Types.SqlGeography.GeographyFromText(OpenGisType type, SqlChars taggedText, Int32 srid)
.]
System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) +2084358
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) +5096328
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() +234
System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) +2294
System.Data.SqlClient.SqlDataReader.ConsumeMetaData() +33
System.Data.SqlClient.SqlDataReader.get_MetaData() +86
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +311
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) +987
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) +162
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +32
System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +141
System.Data.SqlClient.SqlCommand.ExecuteReader() +89
gmaps.Button11_Click(Object sender, EventArgs e) +185
System.Web.UI.WebControls.Button.OnClick(EventArgs e) +118
System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +112
System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +36
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5563
please advise, or if this is for another topic tell me. I'm a beginner with SQL
There are many issues with your code....
1.) You're calling MakeValid() on #g and #h when they are uninitialised variables:
DECLARE #g geography;
DECLARE #h geography;
SET #h = #h.MakeValid();
SET #g = #g.MakeValid();
2.) What is #s for? It's never used...
3.) #g is an invalid, self-intersecting polygon. The appropriate valid instance to represent this pointset is MULTIPOLYGON (((23.483 39.671, 39.692 23.483, 23.721 39.602, 23.483 39.671)), ((23.466 39.8, 23.721 39.602, 24.095 39.493, 23.466 39.8)))
4.) #h has the incorrect ring orientation (that is, assuming that you're not trying to create a Polygon that covers 99% of the earth's surface). It should be POLYGON((39.43195 23.510742, 39.628961 23.128967, 39.800096 23.296509, 39.7093 23.859558, 39.43195 23.510742))
So, your SQL query should be:
DECLARE #g geography;
DECLARE #h geography;
SET #g = geography::STGeomFromText('MULTIPOLYGON (((23.483 39.671, 39.692 23.483, 23.721 39.602, 23.483 39.671)), ((23.466 39.8, 23.721 39.602, 24.095 39.493, 23.466 39.8)))', 4326);
SET #h = geography::STGeomFromText('POLYGON((39.43195 23.510742, 39.628961 23.128967, 39.800096 23.296509, 39.7093 23.859558, 39.43195 23.510742))', 4326);
SELECT #g.STIntersects(#h) as reply;
Which gives the result '1', as represented in SQL Server Spatial Results tab shown below:
Pro Spatial with SQL Server 2012
Related
Error is
The type of column 'MemberHId' is not supported. The type is 'SqlHierarchyId'.
In both the server the datatype is same "HierarchyId".
I am just using the ADO.Net.
The assembly is Microsoft.SqlServer.ManagedDTS version- 13.0.0.0
We are using Azure Sql.
Tried with different versions of sql assemblies
DataTable dt = new DataTable();
dt.Columns.Add("Code", typeof(string));
dt.Columns.Add("Description", typeof(string));
dt.Columns.Add("NodeId", typeof(int));
dt.Columns.Add("MemberHId", typeof(SqlHierarchyId));
dt.Columns.Add("Level", typeof(int));
//Getting the data from serverAPI which is returning the data in the columns without null records.
dt=apicall();
SqlParameter returnParameter = cmd.Parameters.Add("RetVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = spName;
cmd.Parameters.AddWithValue("#MemberH", dt);
cmd.CommandTimeout = 0;
cmd.Connection.Open();
cmd.ExecuteNonQuery();// Its failing here
My Sp consists of table type param #MemberHType and the procedure returns rows with these columns:
Name | Type
------------+----------
Code | varchar
Description | varchar
NodeID | smallint
MemberHId | hierarchyid
Level | smallint
This is the procedure:
alter PROCEDURE [dbo].[InsertHierarchyData]
(
#MemberHType MemberH READONLY
)
AS
truncate table test
BEGIN TRY
insert into test values ('start select')
--create table test (errormessage varchar(1000))
IF EXISTS (SELECT TOP 1 1 FROM #MemberHType)
BEGIN
insert into test values ('Inside first Insert start')
INSERT INTO HierarchyStaging
(
Code
,[Description]
,NodeID
,MemberhHId
,[Level]
)
SELECT
Code
,[Description]
,NodeId
,MemberhHId
,[Level]
FROM #MemberHType
insert into test values ('Inside first Insert end')
END
END TRY
BEGIN CATCH
SELECT #comment = ERROR_MESSAGE()
,#Status = 'Error'
SET #comment = CONVERT(NVARCHAR(3000),#Comment) + ' Error Severity: ' + CAST(ERROR_SEVERITY() AS varchar(25)) + ' Error state: 30'
GOTO ErrorHandler
END CATCH
The Column in c# is SqlHierarchyId.
Stack-trace:
at System.Data.SqlClient.TdsParser.TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc, Boolean sync, TaskCompletionSource`1 completion, Int32 startRpc, Int32 startParam)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
If I understand the documentation correctly, you can't use SqlHierarchyId as the data type of a DataColumn.
It doesn't appear in the System.Data.SqlTypes Namespace, and it also doesn't appear in the SQL Server Data Type Mappings table, which means there's no documented built in conversion between SQL Server's HierarchyId and a built in type in the .Net framework. (of course, undocumented features have been known to exist in SQL Server, but I wouldn't recommend relying on that).
What you can do, however, is to convert the HierarchyId to nvarchar using a simple cast in T-SQL when you read it into your c# application (which internally is calling the ToString() method):
CAST(MemberhHId AS nvarchar(4000)) as MemberHId
and convert it back using cast when you insert the data (which internally is calling the Parse() method):
CAST(MemberHId AS hierarchyid)
I have a C# code which throws me a SQLException with message Error Converting data type varchar to int. Funny thing is I dont have any conversion or INT variables in my code. My stored procedure works fine on its own via SSMS.
Here is the C# bit
string[] envData = new string[4];
string dbCon = "";
dbCon = "Database=" + "TestData";
dbCon = dbCon + ";Server=" + "DEV";
dbCon = dbCon + ";Trusted_Connection=Yes;";
using (SqlConnection Con = new SqlConnection(dbCon))
{
Con.Open();
//using (SqlTransaction tr = Con.BeginTransaction("GetEnvironmentInfo"))
//{
string spEnvironmentInfo = #"ELog.GetEnvironmentInfo";
SqlCommand cmd = new SqlCommand(spEnvironmentInfo, Con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#oElogBaseDir", DbType.String));
cmd.Parameters["#oElogBaseDir"].Direction = ParameterDirection.Output;
cmd.Parameters.Add(new SqlParameter("#oElogFinancialMonthDir", DbType.String));
cmd.Parameters["#oElogFinancialMonthDir"].Direction = ParameterDirection.Output;
cmd.Parameters.Add(new SqlParameter("#oElogFinancialYear", DbType.String));
cmd.Parameters["#oElogFinancialYear"].Direction = ParameterDirection.Output;
cmd.Parameters.Add(new SqlParameter("#oElogEmailAccount", DbType.String));
cmd.Parameters["#oElogEmailAccount"].Direction = ParameterDirection.Output;
try
{
cmd.ExecuteNonQuery();
envData[0] = cmd.Parameters["#oElogBaseDir"].Value.ToString();
envData[1] = cmd.Parameters["#oElogFinancialMonthDir"].Value.ToString();
envData[2] = cmd.Parameters["#oElogFinancialYear"].Value.ToString();
envData[3] = cmd.Parameters["#oElogEmailAccount"].Value.ToString();
//tr.Commit();
}
catch (System.Exception ex)
{
//tr.Rollback("GetEnvironmentInfo");
throw ex;
//return null;
}
//}
}
Response.Write(envData[0].ToString());
Response.Write(envData[1].ToString());
Response.Write(envData[2].ToString());
Response.Write(envData[3].ToString());
and here is the sql part
ALTER PROCEDURE [ELog].[GetEnvironmentInfo]
#oELogBaseDir VARCHAR(MAX) OUTPUT,
#oELogFinancialMonthDir VARCHAR(MAX) OUTPUT,
#oELogFinancialYear VARCHAR(MAX) OUTPUT,
#oElogEmailAccount VARCHAR(MAX) OUTPUT
AS
BEGIN
SELECT
#oELogBaseDir = e.ELogBaseDir,
#oELogFinancialMonthDir = e.ELogFinancialMonthDir,
#oELogFinancialYear = e.ELogFinancialYear,
#oElogEmailAccount = e.ElogEmailAccount
FROM SSISMeta.Environment e
WHERE e.SQLServerInstance = ##SERVERNAME
END
Here is the stack trace
[SqlException (0x80131904): Error converting data type varchar to int.]
System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) +2442126
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) +5736904
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) +628
System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) +3731
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +225
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds, Boolean describeParameterEncryptionRequest) +2026
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite) +375
System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite) +337
System.Data.SqlClient.SqlCommand.ExecuteNonQuery() +280
WebTest_Replacement_OutlookVB.Test_Home.btnReadEmail_Click(Object sender, EventArgs e) in \\LocalDev\Random\WebTest_Replacement_OutlookVB\Test_Home.aspx.cs:70
System.Web.UI.WebControls.Button.OnClick(EventArgs e) +9692746
System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +108
System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +12
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +15
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +35
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3562
Table schema
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
SET ANSI_PADDING ON
GO
CREATE TABLE [SSISMeta].[Environment] (
[SK_EnvironmentID] [smallint] IDENTITY(1, 1) NOT NULL,
[IsProduction] [bit] NOT NULL,
[SQLServerInstance] [varchar](100) COLLATE Latin1_General_CI_AS NOT NULL,
[BaseDirPath] [varchar](4000) COLLATE Latin1_General_CI_AS NOT NULL,
[CreatedTimeStamp] [datetime] NOT NULL,
[LastUpdatedTimeStamp] [datetime] NOT NULL,
[ModifiedBYUser] [varchar](100) COLLATE Latin1_General_CI_AS NOT NULL,
[SharedBaseDir] [varchar](4000) COLLATE Latin1_General_CI_AS NOT NULL,
[SharedT2ODir] [varchar](4000) COLLATE Latin1_General_CI_AS NULL,
[ELogBaseDir] [varchar](4000) COLLATE Latin1_General_CI_AS NOT NULL,
[ELogFinancialMonthDir] [varchar](250) COLLATE Latin1_General_CI_AS NOT NULL,
[ELogFinancialYear] [varchar](250) COLLATE Latin1_General_CI_AS NOT NULL,
[ElogEmailAccount] [varchar](250) COLLATE Latin1_General_CI_AS NOT NULL,
CONSTRAINT [PK_Environment]
PRIMARY KEY
CLUSTERED
([SK_EnvironmentID])
ON [SSISMeta_Data_Fg]
) ON [SSISMeta_Data_Fg]
GO
ALTER TABLE [SSISMeta].[Environment]
ADD
CONSTRAINT [DF_Environment_CreatedTimestamp]
DEFAULT (getdate()) FOR [CreatedTimeStamp]
GO
ALTER TABLE [SSISMeta].[Environment]
ADD
CONSTRAINT [DF_Environment_LastUpdatedTimestamp]
DEFAULT (getdate()) FOR [LastUpdatedTimeStamp]
GO
ALTER TABLE [SSISMeta].[Environment]
ADD
CONSTRAINT [DF_Environment_ModifiedByUser]
DEFAULT (suser_sname()) FOR [ModifiedBYUser]
GO
ALTER TABLE [SSISMeta].[Environment] SET (LOCK_ESCALATION = TABLE)
GO
I knew it was going to be something silly, I need to use SqlDbType not DbType.
Works fine now
I am trying to create a procedure(drop a procedure and remake it with new data) in my .net project. When I run the same query in Database "Create New Query" it works fine, but when I try to run it in c#, it gives me an error.
private void makeprocedure()
{
string sqlProcedureCreate = #"
IF(OBJECT_ID('usp_HourData') IS NOT NULL)
DROP PROCEDURE IF EXISTS usp_HourData;
GO
CREATE PROCEDURE usp_HourData
AS
BEGIN
SELECT Employee.[First Name] + ' ' + Employee.[Last Name] AS 'Name',
sum(Time.[Total Hours]) AS 'Total Hours'
, FORMAT(Time.[Time in], 'd', 'en-gb') AS 'Worked On'
FROM Employee
inner join Time on
Employee.ID ='" + getID() + "' and Time.EmployeeIdFK = '" + getID()
+ "' WHERE Time.[Time in] between '" + CalendarStart.SelectedDate + "' and '" + CalendarEnd.SelectedDate
+ #"'GROUP BY FORMAT(Time.[Time in], 'd', 'en-gb') ,Employee.[First Name] + ' ' +Employee.[Last Name];
END
";
using (SqlCommand command = new SqlCommand(sqlProcedureCreate, con))
{
command.CommandType = CommandType.Text; //I tried command.CommandType = CommandType.StoredProcedure;
con.Open();
command.ExecuteNonQuery(); //Compiler says error is on this line
con.Close();
}
}
The error is near "GO" and "CREATE/ALTER PROCEDURE" must go first.
System.Data.SqlClient.SqlException was unhandled by user code
Class=15
ErrorCode=-2146232060
HResult=-2146232060
LineNumber=4
Message=Incorrect syntax near 'GO'.
'CREATE/ALTER PROCEDURE' must be the first statement in a query batch.
Number=102
Procedure=""
Server=(LocalDB)\MSSQLLocalDB
Source=.Net SqlClient Data Provider
State=1
StackTrace:
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at WebApplication2.Manager.makeprocedure() in D:\Users\Albin\MyClockIn\WebApplication2\WebApplication2\Manager.aspx.cs:line 209
at WebApplication2.Manager.ButtonSearch_Click(Object sender, EventArgs e) in D:\Users\Albin\MyClockIn\WebApplication2\WebApplication2\Manager.aspx.cs:line 161
at System.Web.UI.WebControls.Button.OnClick(EventArgs e)
at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)
at System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument)
at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument)
at System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData)
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
InnerException:
How would I go about this error?
This may not be the answer to your question but just an advice about your programming style. These are bad things in your code:
You are concatenating query string. You should use parameters.
You are creating a procedure where query contains data not the parameters. Stored procedure should contain query with parameters and you should pass data to it.
Stored procedures are not supposed to be dropped and recreated each time you access them. I can clearly see you can achieve the same result by just using the select statement. If you are creating stored procedures there must be some data to pass otherwise there is no point in making a stored procedure.
Enough theory, Let's see things in action:
Here is your MakeProcedure (please rename this) Function:
//Rename this function to some useful name
private void makeprocedure()
{
string query = #" SELECT Employee.[First Name] + ' ' + Employee.[Last Name] AS 'Name',
sum(Time.[Total Hours]) AS 'Total Hours'
, FORMAT(Time.[Time in], 'd', 'en-gb') AS 'Worked On'
FROM Employee
inner join Time on
Employee.ID = #EmpId and Time.EmployeeIdFK = #EmpId WHERE Time.[Time in]
between #StartDate and #EndDate GROUP BY FORMAT(Time.[Time in], 'd', 'en-gb'),
Employee.[First Name] + ' ' +Employee.[Last Name];";
using (SqlCommand command = new SqlCommand(query, con))
{
command.CommandType = CommandType.Text;
command.Parameters.AddWithValue("#EmpId", getID());
command.Parameters.AddWithValue("#StartDate", CalendarStart.SelectedDate);
command.Parameters.AddWithValue("#EndDate", CalendarEnd.SelectedDate);
con.Open();
var reader = command.ExecuteReader();
//do something with data in the reader.
con.Close();
}
}
This is what I want to use;
string insertQuery = #"insert into userinfo (UserName, FirstName, LastName,
E-mail, Password, Country)
values ( '" + uname + "', '" + fname +
"','" + lname + "', '" + email + "')";
where every one of the variables in between the + are string variables with values in them. but when I run this command, I get some incorrect syntax error.
This is the new error i get;
errorSystem.Data.SqlClient.SqlException (0x80131904): String or binary
data would be truncated. The statement has been terminated. at
System.Data.SqlClient.SqlConnection.OnError(SqlException exception,
Boolean breakConnection, Action1 wrapCloseInAction) at
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException
exception, Boolean breakConnection, Action1 wrapCloseInAction) at
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject
stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at
System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,
SqlCommand cmdHandler, SqlDataReader dataStream,
BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject
stateObj, Boolean& dataReady) at
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds,
RunBehavior runBehavior, String resetOptionsString) at
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior
cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean
async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader
ds) at
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior
cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String
method, TaskCompletionSource1 completion, Int32 timeout, Task& task,
Boolean asyncWrite) at
System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1
completion, String methodName, Boolean sendToPipe, Int32 timeout,
Boolean asyncWrite) at
System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at
Registration.RegistrationPage.Button1_Click1(Object sender, EventArgs
e) in c:\Users\kristhnen.jagambrum\Documents\Visual Studio
2012\Projects\Registration\Registration\RegistrationPage.aspx.cs:line
50 ClientConnectionId:6d959e49-5b62-43be-b202-76f7eb1fbd2c
It's very good that you asked - the code that you show is a perfect illustration of two security issues in a single line:
The table structure is an illustration of what lets hackers steal user passwords.
The C# code is what makes SQL injection attacks possible.
Fixing the first problem is hard: you need to learn about password hashing and how to store user info in DB. Here is a Q&A that will help: Best way to store passwords in DB
The second problem is easier - all you need is replacing the injected values with parameter names, and then adding the values for each parameter name:
... // Create SQL command, then set its text
command.CommandTest = #"INSERT INTO userinfo (
UserName, FirstName, LastName, E-mail, Password_hash, Password_salt, Country
) VALUES ( #uname, #fname, #lname, #email, #pwd_hash, #pwd_salt, #country)";
// Bind the parameters
command.Parameters.Add(new SqlParameter("#uname", uname));
command.Parameters.Add(new SqlParameter("#fname", fname));
... // ...and so on
command.ExecuteNonQuery();
The answer is you don't, because it is a bad idea. You should be using SQlCommand instead
Check This out,and there are plenty of examples of how to use it. Appending variables in the way you doing is considered to be the mistake number 3 in the list of 25 most dangerous programming mistakes.
Try something like this, and not use direct parameter in sql command
public const string InsertStmtUsersTable = "insert into userinfo (UserName, FirstName, LastName,
[E-mail], Password, Country) values (#UserName, #FirstName, #LastName,
#[E-mail], #Password, #Country) "
using(SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
using (SqlCommand command = new SqlCommand(InsertStmtUsersTable, conn))
{
command.CommandType = CommandType.Text;
command.Parameters.Add(new SqlParameter("username", userNameString));
command.Parameters.Add(new SqlParameter("FirstName", FirstNameString));
// Rest of your Parameters here
command.ExecuteNonQuery();
}
}
I am trying to insert data in a table (say feedback) with columns from(int) and Message(Varchar(MAX)) via c# code but it is continuously annoying me with errors. Please help, I am desperate.
Table description:
From int,Message Varchar(max)
Code I'm using:
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["SampleConnectionString"].ConnectionString);
con.open;
string query="insert into Feedback (From,Message) values(#frm,#msg)";
SqlCommand comm = new SqlCommand(query, con);
comm.Parameters.AddWithValue("#frm", Convert.ToInt32(TextBoxid.Text));
comm.Parameters.AddWithValue("#msg",TextBoxFeedBack.text);
comm.ExecuteNonQuery();
con.Close();
The Error I'm getting is
System.Data.SqlClient.SqlException (0x80131904): Incorrect syntax near
the keyword 'From'. at
System.Data.SqlClient.SqlConnection.OnError(SqlException exception,
Boolean breakConnection) at
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException
exception, Boolean breakConnection) at
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() at
System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior,
SqlCommand cmdHandler, SqlDataReader dataStream,
BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject
stateObj) at
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds,
RunBehavior runBehavior, String resetOptionsString) at
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior
cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean
async) at
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior
cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String
method, DbAsyncResult result) at
System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult
result, String methodName, Boolean sendToPipe) at
System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at
_Default.Button1_Click(Object sender, EventArgs e) in c:\Users\Ajaz\Documents\Visual Studio
2010\WebSites\WebSite26\Default.aspx.cs:line 29
I'm guessing there's error related to data mismatch. Please help.
Thanks
FROM is a reserved keyword in TSQL. You should use it with square brackets like [FROM]
string query="insert into Feedback ([From],Message) values(#frm,#msg)";
As a general recomendation, don't use reserved keywords for your identifiers and object names in your database.
Also use using statement to dispose your SqlConnection like;
string query = "insert into Feedback ([From],Message) values(#frm,#msg)";
using(SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["SampleConnectionString"].ConnectionString))
{
SqlCommand comm = new SqlCommand(query, con);
comm.Parameters.AddWithValue("#frm", Convert.ToInt32(TextBoxid.Text));
comm.Parameters.AddWithValue("#msg",TextBoxFeedBack.text);
con.Open();
comm.ExecuteNonQuery();
con.Close();
}
"From" is the reserved word. Surround it by square brackets:
string query="insert into Feedback ([From],Message) values(#frm,#msg)";
Well, the word FROM is a well known keyword in any SQL language existing in the world. If you want to use it (very bad move) then you need to encapsulate it in square brackets
string query="insert into Feedback ([From],Message) values(#frm,#msg)";
Again, don't do that, change the name of the column before having to much code to change.
Otherwise you will have this problem for the lifetime of your app.