Pervasive SQL System Stored Procedure from ADO.NET error - c#

I'm just trying to return a list of columns and their attributes through a system stored procedure. What documentation I have seems to say the below code should work, but I get "Pervasive.Data.SqlClient.Lna.k: [LNA][Pervasive][ODBC Engine Interface]Invalid or missing argument." on the execute. This is PSQL v11, .NET 4.5.
using (PsqlConnection conn = new PsqlConnection(cs))
{
PsqlCommand locationCmd = new PsqlCommand();
PsqlParameter tableParam = new PsqlParameter();
PsqlParameter returnParam = new PsqlParameter();
returnParam.Direction = ParameterDirection.ReturnValue;
locationCmd.CommandText = "psp_columns";
locationCmd.Connection = conn;
locationCmd.CommandType = CommandType.StoredProcedure;
locationCmd.Parameters.Add(tableParam).Value = table;
locationCmd.Parameters.Add(returnParam);
conn.Open();
locationCmd.ExecuteNonQuery();
}

I would think the problem is this line:
locationCmd.Parameters.Add(tableParam).Value = table;
You should set the value before adding the parameter, not afterwards.
tableParam.Value = table;
locationCmd.Parameters.Add(tableParam);
I don't know about Psql but for MSSQL normally you also need to define the parameter name as its found in the stored procedure, or at least that's what I do.
SqlParameter param = new SqlParameter("#tableParam", value);

The psp_Columns system stored procedure is defined as call psp_columns(['database_qualifier'],'table_name', ['column_name']). I know that it says the database qualifier is optional, but I think it's required. You could try passing an empty string for the qualifier. Something like:
using (PsqlConnection conn = new PsqlConnection(cs))
{
PsqlCommand locationCmd = new PsqlCommand();
PsqlParameter dbParam = new PsqlParameter();
PsqlParameter tableParam = new PsqlParameter();
PsqlParameter returnParam = new PsqlParameter();
returnParam.Direction = ParameterDirection.ReturnValue;
locationCmd.CommandText = "psp_columns";
locationCmd.Connection = conn;
locationCmd.CommandType = CommandType.StoredProcedure;
locationCmd.Parameters.Add(dbParam).Value = ""; //might need two single quotes ('')
locationCmd.Parameters.Add(tableParam).Value = table;
locationCmd.Parameters.Add(returnParam);
conn.Open();
locationCmd.ExecuteNonQuery();
}

You should try to get the information of the table SCHEMA using the provided GetSchema method from the Psqlconnection. I have searched a bit on their support site and it seems that this method is supported although I haven't find a direct example using the Tables collection.
This is just an example adapted from a test on mine on SqlServer, I don't have Pervasive install, but you could try if the results are the same
using(PsqlConnection cn = new PsqlConnection("your connection string here"))
{
cn.Open();
string[] selection = new string[] { null, null, table };
DataTable tbl = cn.GetSchema("Columns", selection);
foreach (DataRow row in tbl.Rows)
{
Console.WriteLine(row["COLUMN_NAME"].ToString() + " " +
row["IS_NULLABLE"].ToString() + " " +
row["DATA_TYPE"].ToString()
);
}
}

i was trying to figure this out as well, but with the tables procedure. even though the database and table names are optional, you still have to provide values. for optional parameters, pass in DBNull.Value
this worked for me:
PsqlCommand cm = new PsqlCommand();
cm.CommandText = "psp_tables";
cm.CommandType = CommandType.StoredProcedure;
cm.Connection = new PsqlConnection();
cm.Connection.ConnectionString = <your connection string>;
cm.Parameters.Add(":database_qualifier", DBNull.Value);
cm.Parameters.Add(":table_name", DBNull.Value);
cm.Parameters.Add(":table_type", "User table");

Related

C# SQL Server stored procedure not returning expected value

I wrote up this function to return a dataset, I was expecting a smaller dataset as there's only one value I was expecting back, but I get a rather bloated object back which I cannot find the value I am looking for, this is causing problems as I intend to use this function heavily.
I was hoping someone could spot what I am doing wrong, I have included the code, a screenshot of the returned object and what I am expecting. Any help would be greatly appreciated.
If I have not phrased anything in this question correctly feel free to let me know, I struggle to express my thoughts well.
public DataSet getPartnerParameter(string parameter)
{
using (var dbConnection = new SqlConnection(UnityHelper.IocContainer.Resolve<IConfigHelperService>().GetConnectionString("CASConnectionString")))
{
dbConnection.Open();
using (var dbCommand = new SqlCommand("GETPARTNERPARAMETER"))
{
dbCommand.CommandType = CommandType.StoredProcedure;
dbCommand.Connection = dbConnection;
SqlParameter lstrParameter = new SqlParameter("#Parameter", SqlDbType.VarChar);
lstrParameter.Value = parameter;
dbCommand.Parameters.Add(lstrParameter);
var ldaDPS = new SqlDataAdapter(dbCommand);
var ldstParameterValues = new DataSet();
ldaDPS.Fill(ldstParameterValues);
return ldstParameterValues;
}
}
}
This is what I am expecting to find
edit//
changed my code slightly but still not working.
public String[] getPartnerParameter(string parameter)
{
using (var dbConnection = new SqlConnection(UnityHelper.IocContainer.Resolve<IConfigHelperService>().GetConnectionString("CASConnectionString")))
{
dbConnection.Open();
SqlCommand dbCommand = new SqlCommand("GETPARTNERPARAMETER", dbConnection);
dbCommand.CommandType = CommandType.StoredProcedure;
SqlParameter lstrParameter = new SqlParameter("#Parameter", SqlDbType.VarChar);
lstrParameter.Value = parameter;
dbCommand.Parameters.Add(lstrParameter);
SqlDataReader reader = dbCommand.ExecuteReader();
string[] results = new string[2];
while (reader.Read())
{
results[0] = reader[0].ToString();
results[1] = reader[1].ToString();
}
if (results.Length < 1)
{
results[0] = "Cannot find Value";
results[1] = "S";
return results;
}
else
{
return results;
}
}
The error is this:
{"Procedure or function 'GETPARTNERPARAMETER' expects parameter '#Parameter', which was not supplied."}
The values you are looking for are probably in the dataSet.Tables[0].Rows[0] row.
However, if you are expecting one row back, a DataSet object seems like overkill. I would recommend avoiding the SqlDataAdapter/DataSet and instead use a SqlDataReader.
Untested code, but should give you the gist of how to use it:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand dbCommand = new SqlCommand("GETPARTNERPARAMETER", connection);
dbCommand.CommandType = CommandType.StoredProcedure;
SqlParameter lstrParameter = new SqlParameter("#Parameter", SqlDbType.VarChar);
lstrParameter.Value = "LexisNexisCreditConsentRequired";
dbCommand.Parameters.Add(lstrParameter);
SqlDataReader reader = dbCommand.ExecuteReader();
while (reader.Read())
{
var yourValue = reader[0];
var yourDataType = reader[1];
}
}
A DataSet is an object which can contain many tables. It doesn't have to, but it can, and so it also has a number of fields, properties, and methods to support that role.
For this query, look at ldstParameterValues.Tables[0].Rows[0]. Within that row, you can also see the columns with another level of bracket-indexing:
DataRow row = ldstParameterValues.Tables[0].Rows[0];
var column0Value row[0];
var column1Value = row[1];
However, the type for these results is object. You'll need to either cast the values or use one of the GetX() methods on the datarow to get results with a meaningful type.

Search date that appears only table without content c#

this my interface application
if i search by date , Looks like this :
this my code :
string a = dateTimePicker1.Value.ToString("dd/MM/yyyy");
clsAccess db = new clsAccess(DB_PATH);
string query = "";
query = "select * from vwDataMHSSkripsi where Tgl_Sidang = " + a + "";
DataTable dt = db.GetSummaryData(query);
c1FlexGridPencarianSkripsi.DataSource = dt;
db.CloseDatabaseConnection(); db = null;
I want to display the search results but which appear only tables without content
GetSummaryData looks like this:
public System.Data.DataTable GetSummaryData(string SQLStatement)
{
System.Data.DataTable dt = new System.Data.DataTable();
if (conn.State.ToString().Equals("Open"))
{
System.Data.OleDb.OleDbCommand cmd = new System.Data.OleDb.OleDbCommand(SQLStatement, conn);
using (System.Data.OleDb.OleDbDataAdapter rsAdapter = new System.Data.OleDb.OleDbDataAdapter())
{
rsAdapter.SelectCommand = cmd;
rsAdapter.Fill(dt);
}
}
return dt;
}
Thanks...
You can make everything much safer and easier, if you add a GetSummaryData function which accepts parameters. The code for this should look something like:
public System.Data.DataTable GetSummaryData(string SQLStatement,
OleDbParameter[] parameters)
{
System.Data.DataTable dt = new System.Data.DataTable();
if (conn.State == ConnectionState.Open)
{
System.Data.OleDb.OleDbCommand cmd = new System.Data.OleDb.OleDbCommand(SQLStatement, conn);
for (int i = 0; i < parameters.Length; i++)
{
cmd.Parameters.Add(parameters[i]);
}
using (System.Data.OleDb.OleDbDataAdapter rsAdapter = new System.Data.OleDb.OleDbDataAdapter())
{
rsAdapter.SelectCommand = cmd;
rsAdapter.Fill(dt);
}
}
return dt;
}
You can now change the code that calls this in your example to:
string query = "";
query = "select * from vwDataMHSSkripsi where Tgl_Sidang = #mydate";
OleDbParameter[] parameters = new OleDbParameter[1];
OleDbParameter param = new OleDbParameter();
param.ParameterName = "#mydate";
param.OleDbType = OleDbType.Date;
param.Value = dateTimePicker1.Value;
parameters[0] = param;
DataTable dt = db.GetSummaryData(query, parameters);
Please note I have changed your check of conn.State. Please use my one as it is much more efficient to use the correct value, rather than converting to string and then checking for "Open".
ADDENDUM
I deliberately allowed an array of parameters rather than just a single parameter, in case you need to call the same routine elsewhere with more than one parameter. If using more than one, please be careful. When using OleDb the order of parameters is important (and the names by contrast relatively irrelevant); you must add the parameters in the order in which they are referred to in the SQL string.
PS
What I should have pointed out, is that a corollary benefit of this approach, is that you do not need to worry about the format of dates. The parameter takes as its Value a datetime (even though OleDBType is set to Date, this is in fact a datetime). The library handles the interface to the database for you.

Passing multiple SqlParameter to method

In my main form, I have implemented this code..
void SampleMethod(string name, string lastName, string database)
{
SqlParameter sqlParam = new SqlParameter();
sqlParam.ParameterName = "#name";
sqlParam.Value = name;
sqlParam.SqlDbType = SqlDbType.NVarChar;
SqlParameter sqlParam1 = new SqlParameter();
sqlParam1.ParameterName = "#lastName";
sqlParam1.Value = lastName;
sqlParam1.SqlDbType = SqlDbType.NVarChar;
SqlParameter sqlParam2 = new SqlParameter();
sqlParam2.ParameterName = "#database";
sqlParam2.Value = database;
sqlParam2.SqlDbType = SqlDbType.NVarChar;
SampleClass sampleClass = new SampleClass(new DBConn(#serverName, tableName, userName, password));
sampleClass.executeStoredProc(dataGridView1, "sp_sampleStoredProc", sqlParam, sqlParam1, sqlParam2);
}
And in my SampleClass, I have this kind of method.
public DataGridView executeStoredProc(DataGridView dtgrdView, string storedProcName, params SqlParameter[] parameters)
{
try
{
DataTable dt = new DataTable();
sqlDA = new SqlDataAdapter(storedProcName, sqlconn);
sqlDA.SelectCommand.CommandType = CommandType.StoredProcedure;
sqlDA.SelectCommand.CommandTimeout = 60;
// Loop through passed parameters
if (parameters != null && parameters.Length > 0)
{
foreach (var p in parameters)
sqlDA.SelectCommand.Parameters.Add(p);
}
sqlDA.Fill(dt);
dtgrdView.DataSource = dt;
sqlconn.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
sqlconn.Close();
}
return dtgrdView;
}
What I am trying to do is avoid multiple
SqlParameter sqlParam = new SqlParameter()
in my code, I have tried so many solutions for this problem but I didn't get the right answer. I have also tried to research about this but I still couldn't get the right answer.
Please don't mind my naming convention and other codes as I intentionally change many of them :) Thanks.
As an alternative to your solution, try to use already existing one instead, using Dapper (https://github.com/StackExchange/dapper-dot-net).
You still need to use multiple parameters if your stored procedure or query needs it, but this is nicely abstracted for you and this will definatelly reduce the amount of code.
void SampleMethod(string name, string lastName, string database)
{
using(var connection = new SqlConnection(MY_CONNECTION_STRING))
{
var resultListOfRows = connection.Query<ReturnObject>(MY_STORED_PROCEDURE, new {
name = name,
lastName = lastName,
database = database}, commandType: System.Data.CommandType.StoredProcedure);
}
}
First of all, the easiest option would be to use a microORM like Dapper, and retrieve a strongly-typed collection. Gridviews can bind to anything, including strongly typed collections. All this code could become:
using(var con=new SqlConnection(myConnectionString))
{
con.Open();
var result= connection.Query<ResultClass>("sp_MySproc",
new { Name= name, LastName= lastName,Database=database},
commandType: CommandType.StoredProcedure);
return result;
}
Even when using raw ADO.NET, you can create a SqlParameter in one line by using the appropriate constructor . For example, you can create a new nvarchar(n) parameter with:
var myParam=new SqlParameter("#name",SqlDbType.NVarchar,20);
or
var myParam=new SqlParameter("#name",SqlDbType.NVarchar,20){Value = name};
A better idea though is to create the SqlCommand object just once and reuse it. Once you have an initialized SqlCommand object, you can simply set a new connection to it and change the parameter values, eg:
public void Init()
{
_loadCustomers = new SqlCommand(...);
_loadCustomers.Parameters.Add("#name",SqlDbType.NVarChar,20);
...
}
//In another method :
using(var con=new SqlConnection(myConnectionString)
{       
_loadCustomers.Connection=con;
_loadCustomers.Parameters["#name"].Value = myNameParam;
con.Open();
using(var reader=_load.ExecuteReader())
{
//...
}
}
You can do the same thing with a SqlDataAdapter, in fact that's how Windows Forms and Data Adapters are meant to be used since .NET 1.0 .
Instead of creating a new one each time you want to fill your grid, create a single one and reuse it by setting the connection and parameters before execution. You can use the SqlDataAdapter(SqlCommand) constructor to make things a bit cleaner:
public void Init()
{
_loadCustomers = new SqlCommand(...);
_loadCustomers.Parameters.Add("#name",SqlDbType.NVarChar,20);
....
_myGridAdapter = new SqlDataAdapter(_loadCustomers);
...
}
And call it like this:
using(var con=new SqlConnection(myConnectionString))
{
_myGridAdapter.SelectCommand.Connection=con;
_myGridAdapter.SelectCommand.Parameters["#name"].Value =....;
con.Open();
var dt = new DataTable();
_myGridAdapter.Fill(dt);
dtgrdView.DataSource = dt;
return dtgrdView;
}
Separate your Database logic at one place(put sqladapter, sqlcommand etc at one place), Then encapsulate parameters within your command like mentioned below and you don't need to declare sqlparameter separately, add it inside parameters list.
cmdToExecute.Parameters.Add(new SqlParameter("#parameter", value));
Take a look at the complete example below
public DataTable ProdTypeSelectAll(string cultureCode)
{
SqlCommand cmdToExecute = new SqlCommand();
cmdToExecute.CommandText = "dbo.[pk_ProdType_SelectAll]";
cmdToExecute.CommandType = CommandType.StoredProcedure;
DataTable toReturn = new DataTable("ProdType");
SqlDataAdapter adapter = new SqlDataAdapter(cmdToExecute);
cmdToExecute.Connection = _mainConnection;
cmdToExecute.Parameters.Add(new SqlParameter("#CultureName", cultureCode));
_mainConnection.Open();
adapter.Fill(toReturn);
return toReturn;
}
You may be able to use the SqlParameter Constructor (String, Object). Replace:
sampleClass.executeStoredProc(dataGridView1,
"sp_sampleStoredProc",
sqlParam,
sqlParam1,
sqlParam2);
With:
sampleClass.executeStoredProc(dataGridView1,
"sp_sampleStoredProc",
new SqlParameter("#name", (object)name),
new SqlParameter("#lastName", (object)lastName),
new SqlParameter("#database", (object)database));

Stored procedure returns no rows with SqlDataAdapter

I'm new to using SqlDataAdpter and I'm trying to execute a stored procedure. The stored procedure executes successfully but no rows are returned. I've used SQL Server Profiler to monitor the call and it runs successfully (I can copy and execute the query from profiler without modifying it and get results).
I have the following:
public ActionResult Index()
{
SqlConnection conn = null;
DataSet results = null;
try
{
string connectionString = // ... my connection
conn = new SqlConnection(connectionString );
string query = #"usp_mySP";
conn.Open();
SqlDataAdapter sqlAdpt = new SqlDataAdapter(query, conn);
sqlAdpt.SelectCommand.CommandType = CommandType.StoredProcedure;
var dataDate = new SqlParameter { ParameterName = "#DataDate", Value = DateTime.Now };
var idList = new SqlParameter { ParameterName = "#IDList", Value = "1231,2324,0833" };
sqlAdpt.SelectCommand.Parameters.Add(dataDate);
sqlAdpt.SelectCommand.Parameters.Add(idList);
results = new DataSet();
sqlAdpt.Fill(results);
sqlAdpt.Dispose();
}
catch (SqlException e)
{
throw new Exception("Exception:" + e.Message);
}
finally
{
if (conn != null)
conn.Close();
}
return View(results);
}
When I inspect the DataSet through the debugger, it always returns 0 rows.
Please help with what I'm doing wrong?
Note: I've also tried (but do NOT prefer) executing as a SQL command:
EXEC usp_mySP #DataDate, #IDList
and it didn't work either as I got int to varchar conversion errors.
I think you try to add SqlParameter using SqlCommand like this :
SqlCommand cmd = new SqlCommand();
cmd.parameter.addwithvalue(#DataDate,DateTime.Now);
So the reason was because of set nocount on. I added it to my sp and it works. Thank you everyone for clarifying.

connect and read .MDB item with C#

Is it possible to connect to a local MDB file and pick a single bit of info out of it ?
I have a table in a .mbd file with a single bit of info in it. I would like to have that record be output into a disabled textbox for a reference. I believe I can get the DB open, and run the query but no idea what I need to read from it.
thanks
var myDataTable = new DataTable();
using (var conection = new OleDbConnection("Provider=Microsoft.JET.OLEDB.4.0;" + "data source=C:\\menus\\newmenus\\menu.mdb;Password=****"))
{
conection.Open();
var query = "Select siteid From n_user";
var adapter = new OleDbDataAdapter(query, conection);
OleDbCommandBuilder oleDbCommandBuilder = new OleDbCommandBuilder(adapter);
}
To simply read a single field on your database table you could use an OleDbDataReader that could loop over the result and return the field required..
var myDataTable = new DataTable();
using (var conection = new OleDbConnection("Provider=Microsoft.JET.OLEDB.4.0;" + "data source=C:\\menus\\newmenus\\menu.mdb;Password=****"))
{
conection.Open();
var query = "Select siteid From n_user";
var command = new OleDbCommand(query, conection);
var reader = command.ExecuteReader();
while(reader.Read())
textBox1.Text = reader[0].ToString();
}
if you have just one record and just one field then a better solution is the method ExecuteScalar
conection.Open();
// A query that returns just one record composed of just one field
var query = "Select siteid From n_user where userid=1";
var command = new OleDbCommand(query, conection);
int result = (int)command.ExecuteScalar(); // Supposing that siteid is an integer
Probably I should also mention that ExecuteScalar returns null if the query doesn't find a match for the userid, so it is better to be careful with the conversion here
object result = command.ExecuteScalar();
if( result != null)
int userID = (int)result;
.....
Yes very possible. Just have the adapter fill the DataTable, also I don't think you'll need the OleDbCommandBuilder.
using (var conection = new OleDbConnection("Provider=Microsoft.JET.OLEDB.4.0;" + "data source=C:\\menus\\newmenus\\menu.mdb;Password=****"))
{
conection.Open();
var query = "Select siteid From n_user";
var adapter = new OleDbDataAdapter(query, conection);
adapter.Fill(myDataTable);
myTextBox.Text = myDataTable.Rows[0][0].ToString();
}
Also I think using ExecuteScalar would be a better solution, but my answer was tailored to the objects you had already instantiated.
You could use OleDbCommand.ExecuteScalar to retrieve a single value. It is returned as an object and you could cast it to the correct type.
Are you looking for stm like this?
OleDbCommand cmd = new OleDbCommand();
OleDbDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
// read ur stuff here.
}

Categories