1

I am running an sql database for movies and I am working on this function so that whenever a user checks out a movie, the movie would be updated saying it has been checked out, then the checked out movie would be added to a table for checked out movies. I have a code that runs without any errors but my checked out movie does not get added to my checked out table. Code for the gridview that displays the selected movie below:

<asp:ListBox ID="CheckOutList" runat="server" OnSelectedIndexChanged="Get_data" AutoPostBack="true">

        </asp:ListBox>

<asp:Panel ID="panel5" runat="server" Visible="false">
        <asp:GridView id="one_data" AutoGenerateColumns="false" runat="server" DataKeyNames="MovieID">
            <Columns>
                <asp:BoundField DataField="MovieID"
                    HeaderText="Movie ID"/>
                <asp:BoundField DataField="MovieTitle"
                    HeaderText="Movie"/>
                <asp:BoundField DataField="DateChecked"
                    HeaderText="Date Checked"/>
                <asp:BoundField DataField="CheckedOut"
                    HeaderText="Checked Out"/>
            </Columns>
        </asp:GridView>
        <asp:Button runat="server" Text="Choose another Movie" OnClick="GoBack" />
        <asp:Button runat="server" Text="Check Out" OnClick="CheckOut" />
    </asp:Panel>

CS code for checking out the movie:

 public void CheckOut(object sender, EventArgs e)
    {
        get_connection();
        try
        {

            connection.Open();
            command = new SqlCommand("UPDATE Content SET DateChecked=@DateChecked, CheckedOut=@CheckedOut WHERE MovieID=@MovieID", connection);
            command.Parameters.AddWithValue("@DateChecked", DateTime.Now);
            command.Parameters.AddWithValue("@CheckedOut", 'Y');
            //command.Parameters.AddWithValue("@MovieID",);
            command.Parameters.AddWithValue("@MovieID", CheckOutList.SelectedValue);

            reader = command.ExecuteReader();
            one_data.DataSource = reader;
            one_data.DataBind();

            reader.Close();


            command = new SqlCommand("INSERT INTO checkout (MovieID, SubscriberID) VALUES @MovieID, @SubscriberID", connection);
            command.Parameters.AddWithValue("@MovieID", CheckOutList.SelectedValue);
            command.Parameters.AddWithValue("@SubscriberID", loginName.Text);
            command.ExecuteNonQuery();
        }
        catch (Exception err)
        {
            // Handle an error by displaying the information.
            lblInfo.Text = "Error reading the database. ";
            lblInfo.Text += err.Message;
        }
        finally
        {
            connection.Close();
            lblInfo.Text = "Movie Checked Out";

        }
    }

The UPDATE SQL statement does work saying the movie has been taken but the movie does not get added to the checked out table.

Jack Huynh
  • 33
  • 2
  • 10
  • you should read up on how to create Stored Procedures that do the following `SELECT, UPDATE, DELETE` also if there are any relational tables in regards to normalization, I would recommend using JOINS where needed on your SELECTS thus cutting down on so many round trips to the database. If you are using DataTables I would take advantage of that as much as possible to.. do not use the same db Connection to do SELECTS, UPDATES, and DELETES.. create new instances of the Connection object and utilize the `using(){ }` construct too – MethodMan Nov 29 '17 at 00:44
  • What about an update trigger, but your update command would need to know about subscriberID to do that, aka the login name. – lamandy Nov 29 '17 at 00:46
  • 1
    Comments flooding in about using a different approach, and no doubt many of them have merit. But to answer the question you have asked - yes, you can execute multiple statements. What is your code currently doing? Have you set breakpoints and stepped through what happens after `reader.close()`? Note that `ExecuteNonQuery()` can return a number of affected rows, which might prove useful for debugging purposes. – Khyron Nov 29 '17 at 00:49
  • I have a login function the user accesses before this and am using the login text from that for the subscriberID – Jack Huynh Nov 29 '17 at 00:51
  • update triggers are good if used properly in my opinion @lamandy but people abuse them most of the time not to mention, they use them incorrectly. also Khyron in C# it's not advised to use the same connection when doing Selects and Inserts or Updates. – MethodMan Nov 29 '17 at 00:51
  • `reader = command.ExecuteReader();` I would also recommend looking up the `Fill()` method do a google search on the following `C# stackoverflow populating a datatable with the Fill() Method` – MethodMan Nov 29 '17 at 00:55
  • Will look into the Fill method to see how it goes – Jack Huynh Nov 29 '17 at 01:00
  • But why wouldn't my current code not run as it is? – Jack Huynh Nov 29 '17 at 01:00
  • 1
    @JackHuynh - have you tried debugging it? i.e. setting breakpoints and stepping though it. – Alex Nov 29 '17 at 01:03
  • @Alex I tried playing with the code to see, the code executes without errors, I even commented out the first SQL query and it still runs but nothing gets added to the checkout table. – Jack Huynh Nov 29 '17 at 01:07
  • @JackHuynh, one of the core skills in programming is leaning how to use debugger! "Playing around with code" in hopes that it would work is not debugging! – Alex Nov 29 '17 at 01:10

5 Answers5

2

I see some missing concept.

  1. why update use command.ExecuteReader(); while insert use command.ExecuteNonQuery(); .
    I think you should use

ExecuteNonQuery

  1. INSERT INTO checkout (MovieID, SubscriberID) VALUES @MovieID, @SubscriberID .
    This sql syntax need bracket for values :

INSERT INTO checkout (MovieID, SubscriberID) VALUES (@MovieID, @SubscriberID)

I hope this solve yours.

  • Upvote for pointing out the actual syntax error. And, @JackHuynh, the finally block gets executed after the catch block upon the syntax error from the INSERT and thus overwrites the error text message with success. You should put the success marker at the end of the try block not in the finally block. Then you might have noticed the error sooner. (Debugging might also have caught it.) – Rob Parker Sep 24 '20 at 21:23
1

I think you better execute coding in the transaction block. also you can update as following examlpe with ";"

 connection.ConnectionString = connectionString;
 command.CommandText = @"
     UPDATE MultiStatementTest SET somevalue = somevalue + 1;
     UPDATE MultiStatementTest SET" + (generateError ? "WONTWORK" : "") + 
                   " somevalue = somevalue + 2;";
 command.CommandType = System.Data.CommandType.Text;
 command.Connection = connection;
charithsuminda
  • 341
  • 2
  • 9
  • I would not recommend advising the OP to create dynamic sql a stored procedure would be more feasible also OP should read up on Sql Injection to – MethodMan Nov 29 '17 at 00:52
1

Can I execute multiple SQL statements?

Of course you can! You can execute it in a single or multiple SqlCommand. :)

The UPDATE SQL statement does work saying the movie has been taken but the movie does not get added to the checked out table

Are you using a local database? If yes, check out Data not saving permanently to SQL table.

Anyway, I would like to my code for data access which could help you in your development.

Disclaimer: I know that using SqlCommand as parameter is better but I got lazy so here's the string version.

public interface IDAL
{
    void BeginTransaction();
    void EndTransaction();
    void SaveChanges();
    DataTable RetrieveData(string query, [CallerMemberName] string callerMemberName = "");
    string RetrieveString(string query, [CallerMemberName] string callerMemberName = "");
    bool ExecuteNonQuery(string query, [CallerMemberName] string callerMemberName = "");
    bool ExecuteNonQuery(string query, object[] parameters, [CallerMemberName] string callerMemberName = "");
}

public class MSSQLDAL : IDAL, IDisposable 
{
    private bool disposed = false;
    private string _connectionString { get; set; }
    private SqlTransaction _transaction { get; set; }
    private SqlConnection _connection { get; set; }
    private IsolationLevel _isolationLevel { get; set; }
    private bool _isCommitted { get; set; }

    public string ConnectionString
    {
        get { return _connectionString; }
    }

    public MSSQLDAL(string connectionString)
    {
        this.connectionString = _connectionString;
        this._connection = new SqlConnection();
        this._connection.ConnectionString = this._connectionString;
        this._isolationLevel = IsolationLevel.ReadCommitted;
        this._isCommitted = false;
    }

    public void BeginTransaction()
    {
        this.Open();
    }

    public void EndTransaction()
    {
        this.Close();
    }

    public void SaveChanges()
    {
        if(_transaction != null)
        {
            _transaction.Commit();
            this._isCommitted = true;
        }
        this.EndTransaction();
    }

    public DataTable RetrieveData(string query, [CallerMemberName] string callerMemberName = "")
    {
        DataTable dataTable = new DataTable();

        try
        {
            using (SqlCommand command = new SqlCommand())
            {
                command.Connection = _connection;
                command.Transaction = _transaction;
                command.CommandText = query;
                command.CommandType = CommandType.Text;

                using (SqlDataAdapter dataAdapter = new SqlDataAdapter(command))
                {
                    dataAdapter.Fill(dataTable);
                }
            }

            //this.AuditSQL(query, string.Empty);
        }
        catch (Exception ex)
        {
            this.AuditSQL(query, ex.Message, callerMemberName);
        }

        return dataTable;
    }

    public string RetrieveString(string query, [CallerMemberName] string callerMemberName = "")
    {
        string text = string.Empty;

        try
        {
            using (SqlCommand oracleCommand = new SqlCommand())
            {
                oracleCommand.Connection = _connection;
                oracleCommand.Transaction = _transaction;
                oracleCommand.CommandText = query;
                oracleCommand.CommandType = CommandType.Text;

                using (SqlDataReader dataReader = oracleCommand.ExecuteReader())
                {
                    dataReader.Read();

                    text = dataReader.GetValue(0).ToString();
                }
            }

            //this.AuditSQL(query, string.Empty);

        }
        catch (Exception ex)
        {
            this.AuditSQL(query, ex.Message, callerMemberName);
        }

        return text;
    }

    public bool ExecuteNonQuery(string query, [CallerMemberName] string callerMemberName = "")
    {
        bool success = false;

        try
        {
            using (SqlCommand command = new SqlCommand())
            {
                command.Connection = _connection;
                command.Transaction = _transaction;
                command.CommandText = query;
                command.CommandType = CommandType.Text;
                command.ExecuteNonQuery();
            }

            //this.AuditSQL(query, string.Empty);

            success = true;
        }
        catch (Exception ex)
        {
            this.AuditSQL(query, ex.Message, callerMemberName);

            success = false;
        }

        return success;
    }

    public bool ExecuteNonQuery(string query, object[] parameters, [CallerMemberName] string callerMemberName = "")
    {
        bool success = false;

        try
        {
            using (SqlCommand command = new SqlCommand())
            {
                command.Connection = _connection;
                command.Transaction = _transaction;
                command.CommandText = query;
                command.CommandType = CommandType.Text;
                command.Parameters.AddRange(parameters);

                command.ExecuteNonQuery();
            }

            //this.AuditSQL(query, string.Empty);

            success = true;
        }
        catch (Exception ex)
        {
            this.AuditSQL(query, ex.Message, callerMemberName);

            success = false;
        }

        return success;
    }

    private void Open()
    {
        if(_connection.State == ConnectionState.Closed)
        {
            _connection.Open();
            _transaction = _connection.BeginTransaction(_isolationLevel);
        }            
    }

    private void Close()
    {
        if (!this._isCommitted)
        {
            if (this._transaction != null)
            {
                this._transaction.Rollback();
            }
        }
        if(this._connection.State == ConnectionState.Open)
        {
            this._connection.Close();
        }
    }

    private void AuditSQL(string query, string message, string callerMemberName = "")
    {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.AppendLine("**************************************************************************************************");
        stringBuilder.AppendLine(string.Format("DATETIME: {0}", DateTime.Now.ToString("MM/dd/yyyy HHmmss")));
        stringBuilder.AppendLine(string.Format("SQL: {0}", query));
        stringBuilder.AppendLine(string.Format("MESSAGE: {0}", message));
        if (!string.IsNullOrWhiteSpace(callerMemberName))
        {
            stringBuilder.AppendLine(string.Format("METHOD: {0}", callerMemberName));
        }
        stringBuilder.AppendLine("**************************************************************************************************");

        Logger.WriteLineSQL(stringBuilder.ToString()); // Log the query result. Add an #if DEBUG so that live version will no longer log.
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                if (!this._isCommitted)
                {
                    if (this._transaction != null)
                    {
                        this._transaction.Rollback();
                    }
                }
                this._transaction.Dispose();
                this._connection.Dispose();
            }
            // Free your own state (unmanaged objects).
            // Set large fields to null.
            // Free other state (managed objects).
            this._transaction = null;
            this._connection = null;
            disposed = true;
        }
    }
}

Sample usage:

public void CheckOut(object sender, EventArgs e)
{
    string connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; // Assuming it is in your web.config

    try
    {
        using(MSSQLDAL dal = new MSSQLDAL(connectionString))
        {
            dal.BeginTransaction();

            string updateQuery = "UPDATE Content SET DateChecked=@DateChecked, CheckedOut=@CheckedOut WHERE MovieID=@MovieID";

            SqlParameter uDateChecked = new SqlParameter("DateChecked", SqlDbType.DateTime);
            uDateChecked = DateTime.Now;
            SqlParameter uCheckedOut = new SqlParameter("CheckedOut", SqlDbType.VarChar);
            uCheckedOut = 'Y';
            SqlParameter uMovieID = new SqlParameter("MovieID", SqlDbType.Int);
            uMovieID = CheckOutList.SelectedValue;

            ICollection<SqlParameter> updateParameters = new List<SqlParameter>();

            updateParameters.Add(uDateChecked);
            updateParameters.Add(uCheckedOut);
            updateParameters.Add(uMovieID);

            bool updateSuccessful = dal.ExecuteNonQuery(updateQuery, updateParameters.ToArray()); 

            string insertQuery = "INSERT INTO checkout (MovieID, SubscriberID) VALUES (@MovieID, @SubscriberID)";

            SqlParameter iSubscriberID = new SqlParameter("SubscriberID", SqlDbType.VarChar);
            iSubscriberID = loginName.Text;
            SqlParameter iMovieID = new SqlParameter("MovieID", SqlDbType.Int);
            iMovieID = CheckOutList.SelectedValue;

            ICollection<SqlParameter> insertParameters = new List<SqlParameter>();

            insertParameters.Add(iSubscriberID);
            insertParameters.Add(iMovieID);

            bool insertSuccessful = dal.ExecuteNonQuery(insertQuery, insertParameters.ToArray()); 

            if(updateSuccessful && insertSuccessful)
            {
                dal.SaveChanges();

                lblInfo.Text = "Movie Checked Out";
            }
            else
            {
                lblInfo.Text = "Something is wrong with your query!";
            }
        }   
    }
    catch(Exception ex)
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("Error reading the database.");
        sb.AppendLine(ex.Message);
        if(ex.InnerException != null)
            sb.AppendLine(ex.InnerException.Message);

        lblInfo.Text = sb.ToString();
    }
}

How can I execute multiple SQL statements in a single command?

You simply need to encapsulate your queries with a BEGIN and END;.

Ex:

BEGIN
    SELECT 'A';
    SELECT * FROM TableA;
END;

Take note that you need to have ; after your statements. I'd use a StringBuilder to write my long queries if I were you. Also, sending multiple queries as one is only useful if you are not reading any data.

What's the IDAL interface for?

In some of my projects I had to work with different databases. Using the same interface, I am able to create a DAL class for Oracle, MSSql and MySql with very minimal code change. It is also the OOP way. :)

jegtugado
  • 5,081
  • 1
  • 12
  • 35
0

Please change the code like this and try.change the reader.close() after executenonquery().

try
        {

            connection.Open();
            command = new SqlCommand("UPDATE Content SET DateChecked=@DateChecked, CheckedOut=@CheckedOut WHERE MovieID=@MovieID", connection);
            command.Parameters.AddWithValue("@DateChecked", DateTime.Now);
            command.Parameters.AddWithValue("@CheckedOut", 'Y');
            //command.Parameters.AddWithValue("@MovieID",);
            command.Parameters.AddWithValue("@MovieID", CheckOutList.SelectedValue);

            reader = command.ExecuteReader();
            one_data.DataSource = reader;
            one_data.DataBind();




            command = new SqlCommand("INSERT INTO checkout (MovieID, SubscriberID) VALUES @MovieID, @SubscriberID", connection);
            command.Parameters.AddWithValue("@MovieID", CheckOutList.SelectedValue);
            command.Parameters.AddWithValue("@SubscriberID", loginName.Text);
            command.ExecuteNonQuery();

           reader.Close();
        }
Revathi Vijay
  • 1,238
  • 1
  • 13
  • 25
0

I finally found an answer after reading all the posts and found that this actually got my INSERT to work

try
        {

            connection.Open();
            command = new SqlCommand("UPDATE Content SET DateChecked=@DateChecked, CheckedOut=@CheckedOut WHERE MovieID=@MovieID", connection);
            command.Parameters.AddWithValue("@DateChecked", DateTime.Now);
            command.Parameters.AddWithValue("@CheckedOut", 'Y');
            //command.Parameters.AddWithValue("@MovieID",);
            command.Parameters.AddWithValue("@MovieID", CheckOutList.SelectedValue);

            //reader = command.ExecuteReader();
            command.ExecuteNonQuery();
            one_data.DataSource = reader;
            one_data.DataBind();
            connection.Close();



            connection.Open();
            command = new SqlCommand("INSERT INTO checkout (MovieID, SubscriberID) VALUES (@MovieID, @SubscriberID)", connection);
            command.Parameters.AddWithValue("@MovieID", CheckOutList.SelectedValue);
            command.Parameters.AddWithValue("@SubscriberID", loginName.Text);
            command.ExecuteNonQuery();
            //reader.Close();
        }
Jack Huynh
  • 33
  • 2
  • 10
  • This is not a good way because you keep closing and opening connections. Best way is to do it in one connection open. – Mert Serimer May 25 '18 at 17:34