13

I want to execute a .sql script from C#. Basically the script inserts a row into few different tables.

The point is I have values in C# code that I need to pass to the .sql query. These values will be collected during program execution.

Here is the query that I want to execute from C# code:

INSERT INTO [DB].[dbo].[User]
           ([Id]
           ,[AccountId]
           ,[FirstName]
           ,[LastName]
           ,[JobTitle]
           ,[PhoneNumber]
          )
     VALUES
           ('00A640BD-1A0D-499D-9155-BA2B626D7B68'
           ,'DCBA241B-2B06-48D7-9AC1-6E277FBB1C2A'
           ,'Mark'
           ,'Wahlberg'
           ,'Actor'
           ,'9889898989'])
GO

The values will vary from time to time i.e., they are captured in C# code and need to be passed.

Can anyone please help me do this..I am learning both C# and SQL. Thanks a lot.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Marc Spencer
  • 357
  • 1
  • 3
  • 12
  • 1
    I think you should try some [**tutorials**](http://www.codeproject.com/Articles/4416/Beginners-guide-to-accessing-SQL-Server-through-C) first, and then ask particular questions here. I find it hard to belive that you didn't get any answer on google. – danielQ Aug 10 '12 at 16:02
  • 1
    sure.. thanks for the link.. newbie on a deadline. hence went for stackoverflow to save my day... – Marc Spencer Aug 10 '12 at 16:16
  • 1
    what, if an actor has name O'Hara ? – Jacek Cz Feb 13 '17 at 17:21

6 Answers6

31

You could open yourself up to SQL injection attacks here, so best practice is to use parameters:

using (SqlConnection dbConn = new SqlConnection(connectionString))
{
    dbConn.Open();

    using (SqlTransaction dbTrans = dbConn.BeginTransaction())
    {
        try
        {
            using (SqlCommand dbCommand = new SqlCommand("insert into [DB].[dbo].[User] ( [Id], [AccountId], [FirstName], [LastName], [JobTitle], [PhoneNumber] ) values ( @id, @accountid, @firstname, @lastname, @jobtitle, @phonenumber );", dbConn))
            {
                dbCommand.Transaction = dbTrans;

                dbCommand.Parameters.Add("id", SqlType.VarChar).Value = id;
                dbCommand.Parameters.Add("accountid", SqlType.VarChar).Value = accountId;
                dbCommand.Parameters.Add("firstname", SqlType.VarChar).Value = firstName;
                dbCommand.Parameters.Add("lastname", SqlType.VarChar).Value = lastName;
                dbCommand.Parameters.Add("jobtitle", SqlType.VarChar).Value = jobTitle;
                dbCommand.Parameters.Add("phonenumber", SqlType.VarChar).Value = phoneNumber;

                dbCommand.ExecuteNonQuery();
            }

            dbTrans.Commit();
        }
        catch (SqlException)
        {
            dbTrans.Rollback();

            throw; // bubble up the exception and preserve the stack trace
        }
    }

    dbConn.Close();
}

This is a good article for beginners with ADO.Net

EDIT - Just as a bit of extra info, I've added a transaction to it so if the SQL command fails it will rollback.

Paul Aldred-Bann
  • 5,840
  • 4
  • 36
  • 55
  • Nice answer. Note you could consider using SqlDbType.UniqueIdentifier or GUID for the first two parameters – dash Aug 10 '12 at 16:00
  • @dash yep you certainly could, there's quite a lot to ADO.Net (far more than you can put in a stackoverflow answer) so I've just summarised the basics. – Paul Aldred-Bann Aug 10 '12 at 16:01
  • Ditto! This is how I would do it! – Matthew Layton Aug 10 '12 at 16:02
  • Actually, I take it back (not the nice answer bit!) - those actually don't seem to be GUID's and hence VarChar is far more appropriate. – dash Aug 10 '12 at 16:06
  • 1
    `dbConn.Close();` is not necessary, the connection is closed by the `using` block – hyankov Mar 16 '17 at 12:26
  • `dbTrans` is not necessary. The insert is atomic already. You only need a transaction if you have more than a single operation. For example read and write, or two writes, etc. – John Henckel Sep 25 '18 at 19:03
  • @dash I know this is a late comment, I just wanna ask something: Right now is `SqlDbType` the only option to define parameter's type? – Simo Jan 22 '19 at 11:03
  • 1
    @Simo not sure what your intention is... it's certainly the only option to ensure that the intended type is intrinsic to the database platform you're using. – Paul Aldred-Bann Feb 05 '19 at 12:05
4
    using SqlCommand cmd= conn.CreateCommand())
    {
                        cmd.CommandText = @"INSERT INTO TABLE (COLUMNS) VALUES (@Id, @account etc...


                        cmdUser.Parameters.Add(new SqlParameter("@User", SqlDbType.UniqueIdentifier) { Value = UserTypeID });
                        cmdUser.Parameters.Add(new SqlParameter("@Id", SqlDbType.UniqueIdentifier) { Value = ApprovalTypeID });
                        cmdUser.Parameters.Add(new SqlParameter("@AccountId", SqlDbType.UniqueIdentifier) { Value = UserID });
                        cmdUser.Parameters.Add(new SqlParameter("@FirstName", SqlDbType.NVarChar, 100) { Value = Name });
                        cmdUser.Parameters.Add(new SqlParameter("@JobTitle", SqlDbType.NVarChar, 100) { Value = Surname });
                        cmdUser.Parameters.Add(new SqlParameter("@PhoneNumber", SqlDbType.Bit) { Value = Active });
    cmdUser.ExecuteNonQuery();
}
SpaceApple
  • 1,309
  • 1
  • 24
  • 46
2
        try
        {
            using (SqlConnection cn = new SqlConnection(this.ConnectionString))
            {
                SqlCommand cmd = new SqlCommand("Insert_User", cn);
                cmd.CommandType = CommandType.StoredProcedure;
                if (cn.State != ConnectionState.Open)
                    cn.Open();
                cmd.Parameters.Add("Id", SqlDbType.NVarChar).Value = "00A640BD-1A0D-499D-9155-BA2B626D7B68";
                cmd.Parameters.Add("AccountId", SqlDbType.NVarChar).Value = "DCBA241B-2B06-48D7-9AC1-6E277FBB1C2A";
                cmd.Parameters.Add("FirstName", SqlDbType.NVarChar).Value = "Mark";
                cmd.Parameters.Add("LastName", SqlDbType.NVarChar).Value = "Wahlberg";
                cmd.Parameters.Add("JobTitle", SqlDbType.NVarChar).Value = "Actor";
                cmd.Parameters.Add("PhoneNumber", SqlDbType.NVarChar).Value = "9889898989";

                return cmd.ExecuteNonQuery();
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }

and for stored procedure, in sql:

    create procedure [Insert_User]
(
@id as nvarchar(100),
@accid as nvarchar(100),
@fname as nvarchar(100),
@lname as nvarchar(100),
@jobtitle as nvarchar(100),
@phone as nvarchar(100)
)
    INSERT INTO [DB].[dbo].[User]
               ([Id]
               ,[AccountId]
               ,[FirstName]
               ,[LastName]
               ,[JobTitle]
               ,[PhoneNumber]
              )
         VALUES
               (@id
               ,@accid
               ,@fname
               ,@lname
               ,@jobtitle
               ,@phone])

also, you can use text boxes or other input type controls to set values. You can change dataType, as you wish, such as uniqueidentifier, int, etc. If one or more of values are set as identifire, eg. AccountID, remove them from query.

Mazdak Shojaie
  • 1,620
  • 1
  • 25
  • 32
2

Frankly, ADO.NET makes it hard to do things like this correctly. Tools like Dapper exist to make that easier:

dbConn.Execute(
     @"insert into [DB].[dbo].[User] ( [Id], [AccountId], [FirstName], [LastName],
                                       [JobTitle], [PhoneNumber] )
       values ( @id, @accountId, @firstName, @lastName, @jobTitle, @phoneNumber )",
       new { id, accountId, firstName, lastName, jobTitle, phoneNumber });

This will deal with all the parameterization for you, efficiently, effectively, and safely.

There are similar APIs for executing queries and populating objects.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
0

The above answers definitely good solutions for the question. However, I would like to recommend more dynamic and robust solution.

Here is your controller (in my example Ajax call)

public JsonResult RecordThis(FormCollection fc)
{
    SqlRecord.RecordThis(fc);
    return View();
}

Then, on your Model (in example SqlRecord) create "Record" function;

public static void Record(FormCollection fc)
{
   var sql = "INSERT INTO RecordTable VALUES ('@Email','@Name','GETDATE()')";
   var parameters = BuildSqlParams(fc);
   ExecuteInlineSqlWithParams(sql, yourconnectionstringhere, parameters);
}

Then, add these two functions below to be used for any function like "Record". You can add conditions as well such as excluding tokens.

public static List<SqlParameter> BuildSqlParams(FormCollection fc)
{
     var parameters = new List<SqlParameter>();
     foreach(var key in fc.AllKeys)
     {   
         if(key != "__RequestVerificationToken")
            parameters.Add(new SqlParameter("@"+key+"", fc[key]));
     }
     return parameters;
}

public static void ExecuteInlineSqlWithParams(string sql, string cnn, List<SqlParameter> parameters )
{
   var connection = new SqlConnection(cnn);
   var command = new SqlCommand(sql, connection);
   command.CommandType = CommandType.Text;
   foreach(var param in parameters)
   {
      command.Parameters.Add(param);
   }
   using (connection)
   {
      connection.Open();
      command.ExecuteNonQuery();
      connection.Close();
   }
}
esenkaya
  • 99
  • 4
-1

You'll need the System.Data.SqlCommand class.

Change the fixed values to named parameters. For example:

INSERT INTO [TABLE] (Column1) values (@Value1) // the @Value1 is the named parameter

Example:

var connection = new SqlConnection("connectionstring");
var command = connection.CreateCommand();
command.CommandText = "insert...."; // sql command with named parameters

// set the named parameter values
command.Parameters["@Value1"] = "Mark wa...";

// execute 
command.ExecuteNonQuery();

SqlCommand reference: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.aspx

Marcelo De Zen
  • 9,439
  • 3
  • 37
  • 50