0

I have a C# form with a MaskedTextBox that I am needing to pass as a parameter to my SQL Server.

The form:

+-------------------------------------------------------+
|                     ___________                       |
|               Date:|__/__/_____|   <---MaskedTextBox  |
|                                                       |
|                     _________                         |
|                    |btnSubmit|     <---Button         |
|                                                       |
+-------------------------------------------------------+

When a date is entered in the MaskedTextBox, it looks for a file matching that date, reads from it, and then sends that data to my SQL Server. However, I'm needing to create a stored procedure to delete the data matching the day of the import- as to not have duplicated data.

The tricky part is that I have the method for sending the data to my SQL Server on another .cs file that is added to my project.

The method(Methods.cs):

public void SendTable(DataTable table, string StoredProcedure, string TableType)
{

    string conStr = "Data Source=" + ConfigurationManager.AppSettings["DataSource"] + "Initial Catalog=" + ConfigurationManager.AppSettings["InitialCatalog"] + "Integrated Security=True;";

    //Use Stored procedure to send data table
    using (SqlConnection connection = new SqlConnection(conStr))
    {
        SqlCommand cmd = new SqlCommand();

        cmd.Connection = connection;
        cmd.CommandText = StoredProcedure;

        connection.Open();

        cmd.CommandType = CommandType.StoredProcedure;

        var fm = new frmMain();  //Main form located in frmMain.cs
        string date = fm.uDate;  //setting string date to a public string, also on frmMain.cs

        SqlParameter dtparam = new SqlParameter("@date", table);
        dtparam.SqlDbType = SqlDbType.Structured;
        dtparam.TypeName = "dbo." + TableType;

        cmd.Parameters.Add(dtparam).Value = date;

        cmd.ExecuteNonQuery();  //ERROR HERE: Failed to convert parameter value from a String to a IEnumerable`1

    }
}

Here is uDate(frmMain.cs):

public string uDate
{
    get { return mtbDate.Text; }
}

In case it's needed, my stored procedure:

ALTER Procedure [dbo].[Submit]
--Add Parameter
@date AS nvarchar(max)
AS
Begin 
    Set NoCount ON

    --DELETE FROM _table

    Begin Tran T1;

    INSERT INTO [Archive]([Customer Name], IDNbr, City, Bal, ONbr, BalDate) SELECT CustName, IDNbr, City, Bal, ONbr, (@date) AS BalDate FROM myView;

    Commit Tran T1;

End

Thank you in advance for any help or advice! If anything is unclear, I will gladly attempt to clarify. I have looked into Passing parameter to SQL Server. I've attempted to correct my code where I thought mistakes were made, though I'm still erroring.

How can I pass the entered date on my frmMain to my SQL Server as a parameter @date ?

EDIT:

When btnSubmit is clicked:

private void btnSubmit_Click(object sender, EventArgs e)
{
    string date = uDate;
    string day = date.Substring(3, 2);
    string month = date.Substring(0, 2);
    string year = date.Substring(8);
    string conStr = "Data Source=" + ConfigurationManager.AppSettings["DataSource"] + "Initial Catalog=" + ConfigurationManager.AppSettings["InitialCatalog"] + "Integrated Security=True;";

    using (var conn = new SqlConnection(conStr))
    {
        conn.Open();

        SqlCommand cmd = new SqlCommand("Submit", conn);
        cmd.CommandType = CommandType.StoredProcedure;                
    }            

    string suffix = @"\myFile.txt";
    date = year + month + day;
    string prefix = @"\\myDirectory\";
    string fileName = prefix + date + suffix;

    ImportList(fileName);
}

ImportList() then collects the data, reads through the file, and then sends the data through another method located on Method.cs:

public void Send(string StoredProcedure, string TableType)
{
    DataTable table = new DataTable();
    DataRow Row;

    //Gets Column info from list and creates columns in table         
    foreach (var column in ExportList[0])
    {
        table.Columns.Add(column.Key, column.Value.GetType());
    }

    foreach(var item in ExportList)
    {
        Row = table.NewRow();

        foreach (var column in item)
        { 
            Row[column.Key] = column.Value;     
        }

        table.Rows.Add(Row);
    }

    //send data table to stored procedure
    SendTable(table, StoredProcedure, TableType);
}
Lauren Rutledge
  • 1,195
  • 5
  • 18
  • 27
Jaskier
  • 1,075
  • 1
  • 10
  • 33
  • 1
    How does the `SendTable` get called when you click the button? Creating a new form does not reference the existing one, you should be passing the date as another parameter to the `SendTable` method. – Ron Beyer Aug 29 '18 at 14:34
  • 2
    Also you should use and store dates as dates, not strings – Ňɏssa Pøngjǣrdenlarp Aug 29 '18 at 14:36
  • @RonBeyer I have added the calls to `EDIT` @Plutonix I figured it would've been easier to store them as strings since they were coming from a textbox. Is there another way to go about that? – Jaskier Aug 29 '18 at 14:48
  • If you actually want to send a structured table to your stored procedure then your `INSERT` doesn't make any sense and you have defined the parameter incorrectly in the stored procedure. Can you explain what you want the procedure to accomplish? – Crowcoder Aug 29 '18 at 14:52
  • 1
    There are so many things wrong here. You never set the command text in SendTable. You are using the wrong datatype for dates. You attempt to pass a user defined type but the parameter is not a user defined type. No idea what the Send method is for, it never gets called in the posted code. This thing is just all over the place. – Sean Lange Aug 29 '18 at 14:53
  • In your `SendTable` method you instantiate a new instance of `frmMain`, and then grab the `uDate` property from it, but you never show it to the user, which means you'll always be getting the default value. Shouldn't you be displaying the form to the user and only getting the date after they enter it? This sounds like the old question, "How do I send data from one form to another?", which has been answered multiple times on this site. – Rufus L Aug 29 '18 at 14:54
  • Possible duplicate of [Send values from one form to another form](https://stackoverflow.com/questions/1559770/send-values-from-one-form-to-another-form) – Rufus L Aug 29 '18 at 14:57
  • @Crowcoder, the `INSERT` statement is inserting data from a view that is calling data from other tables. The other tables are updated within the `ImportList()` method that is called at the end of the `btnSubmit_Click`. @SeanLange, `Send()` is called within the `ImportList()` method. I wasn't sure if it was too much code to put into one post and I didn't seem to have issues with that method. I can add it if needed. – Jaskier Aug 29 '18 at 14:57
  • @Symon I see that but if `@date` is a table then the query would not work because it is invalid SQL. – Crowcoder Aug 29 '18 at 14:59
  • @RufusL The users are shown the form in order to enter the date. Does this not then change the value to be passed? Also: the link you have input was another post I looked into while trying to get the information from one file to another. I though I had done just that, and didn't not include that link within my post. – Jaskier Aug 29 '18 at 14:59
  • In the `SendTable` method you are instantiating a **new** form (and never calling `fm.Show()`, not using the existing one that the users may have entered any data into. – Rufus L Aug 29 '18 at 15:00
  • @Crowcoder `@date` is a parameter, not a table. I'm wanting to set `@date` equal to the date entered on the form and then pass that value to the SQL Server to be used within the stored procedure – Jaskier Aug 29 '18 at 15:01
  • @Symon OK, that is one of the things that is unclear. In that case do not make the SqlParameter type Structured and do not assign the data table to its value. – Crowcoder Aug 29 '18 at 15:02
  • @RufusL Is there a way to get that value without having to open the new form? Since the form would already be open, I don't see a reason to open it again. – Jaskier Aug 29 '18 at 15:19
  • 1
    Well, without seeing all your code, one way would be to add a parameter called "date" to `ImportList`, `Send` and `SendTable`, then you could pass the `uDate` value from the `Click` event (which we know has access to the form fields) to `ImportList`, which passes it to `Send`, which passes it to `SendTable`. – Rufus L Aug 29 '18 at 15:31

2 Answers2

2

You set the data type of @date to a structured type (think table) rather than a nvarchar. The provider is trying to enumerate through the structured parameter.

Change

dtparam.SqlDbType = SqlDbType.Structured;

To

dtparam.SqlDbType = SqlDbType.NVarChar;
Fix
  • 198
  • 1
  • 12
1

I believe the problem is in your construction of the parameter.

SqlParameter dtparam = new SqlParameter("@date", table);

That constructor is taking the second parameter as the value. Here is a modified snippet of your code that should work better.

 ...
 SqlParameter dtparam = new SqlParameter("@date", date);
 dtparam.SqlDbType = SqlDbType.NVarChar;
 dtparam.TypeName = "dbo." + TableType;
 ...

Edit: Fikse is right you also need to not set your type to structured

James
  • 168
  • 8