I have a SQLite table which I've created and it works fine when inserting data which is non-zero. However, I need to insert some zero default values and the SQLiteParameter seems to be converting the zero values to null
Can someone explain why I'm getting #xxxx3=null instead of #xxxx3=0 and also how to fix it.
This appears to happen for any numeric field (INTEGER/NUMERIC).
I've put together a simplified example that shows the problem
class Program
{
private static List<SQLiteParameter> DefaultSystemParameters()
{
List<SQLiteParameter> sp = new List<SQLiteParameter>()
{
new SQLiteParameter("#xxxx2", 60),
//new SQLiteParameter("#xxxx3", 1), // Works fine
new SQLiteParameter("#xxxx3", 0), // Throws 'System.Data.SQLite.SQLiteException' NOT NULL constraint failed: tblxxxx.xxxx3
};
return sp;
}
static void Main(string[] args)
{
//Add Nuget package - System.Data.SQLite v 1.0.99
string baseDir = AppDomain.CurrentDomain.BaseDirectory + AppDomain.CurrentDomain.RelativeSearchPath + "db\\";
string fileName = "test.db";
string sqlCreateTable = "CREATE TABLE IF NOT EXISTS tblxxxx (" +
"xxxx1 INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," +
"xxxx2 INTEGER NOT NULL," +
"xxxx3 INTEGER NOT NULL" +
")";
string sqlInsert = "INSERT INTO tblxxxx (xxxx2, xxxx3) VALUES (#xxxx2, #xxxx3)";
if (!Directory.Exists(baseDir))
Directory.CreateDirectory(baseDir);
DataTable dt = new DataTable();
string connectionString = $"Data Source={baseDir + fileName};Version=3;";
using (var connection = new SQLiteConnection(connectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
//CREATE
using (SQLiteCommand command = new SQLiteCommand(sqlCreateTable, connection))
{
command.CommandType = CommandType.Text;
command.ExecuteNonQuery();
//INSERT
command.CommandText = sqlInsert;
command.Parameters.AddRange(DefaultSystemParameters().ToArray());
command.ExecuteNonQuery();
}
transaction.Commit();
}
}
}
}
From https://msdn.microsoft.com/en-us/library/0881fz2y(v=vs.110).aspx:
Use caution when you use this overload of the SqlParameter constructor
to specify integer parameter values. Because this overload takes a
value of type Object, you must convert the integral value to an Object
type when the value is zero, as the following C# example demonstrates.
Parameter = new SqlParameter("#pname", (object)0);
Related
So, I'm trying to execute a stored procedure from a string to get a wide range of data but I get a
The data reader has more than one field. Multiple fields are not valid for EDM primitive or enumeration types
How do I probably execute my stored procedure
public class CarBLL
{
public static string GetCar(string carnumberxx, string authTicketxx)
{
using (var context = new SindalDBEntities())
{
var doerTicket = "0x0100000067294c938207c9e5e0cb6b98ddc4edd9464bc14e68b59cbc73c9dc559c5d43ad9b3705d1720a52542e0220b7df11b2e4bd913d873b1aa18c";
var stamdata = "G0057";
String sql =
"SET NOCOUNT ON; " +
"EXEC [file].[usp_getCar] " +
"#p_CarNumber= '" + stamdata + "', " +
"#p_DoerTicket= '" + doerTicket + "' ";
List<SqlParameter> sqlParams = new List<SqlParameter>();
sqlParams.Add(new SqlParameter("CarNumber", System.Data.SqlDbType.VarChar, 100, stamdata));
sqlParams.Add(new SqlParameter("DoerTicket", System.Data.SqlDbType.VarChar, 100, doerTicket));
return context.Database.SqlQuery<string>(sql).FirstOrDefault<string>();
}
}
}
}
If I try to exclude one of my parameters from the SP as
public static usp_getCar_Result GetCar(string carnumber, string authTicket)
{
using (var context = new SindalDBEntities())
{
int? id = null;
// ObjectParameter Id = new ObjectParameter("p_ID", typeof(global::System.Int32));
// ObjectResult result = new ObjectResult("usp_getCar_Result", typeof(string));
return context.usp_getCar(id, carnumber, authTicket).FirstOrDefault();
}
}
}
}
I gets a
Additional information: The data reader is incompatible with the specified 'SindalDbModel.usp_getCar_Result'. A member of the type, 'ID1', does not have a corresponding column in the data reader with the same name.
It's better to import your usp_getCar stored procedure to your DbContext. See this tutorial.
In this case you will have a strongly typed method in your SindalDBEntities. So you will be able to just execute it:
return context.GetCar(stamdata, doerTicket).FirstOrDefault();
I am trying to make an oledb connection to an Access database to insert a new record and retrieving the key generated all at once. The code is this:
private static int createUser(OleDbConnection accessConn)
{
try
{
accessConn.Open();
//DbCommand also implements IDisposable
using (OleDbCommand cmd = accessConn.CreateCommand())
{
//create command with placeholders
cmd.CommandText =
"INSERT INTO EmployeeFiles " +
"([FirstName], [LastName], [JobTitleID], [SecurityLevel], [RowGUID])" +
"VALUES(#FirstName, #LastName, #JobTitleID, #SecurityLevel, #RowGUID)";
//Set Parameters
string FirstName = "Dick";
string LastName = "Tracy";
int JobTitleID = 11;
string SecurityLevel = "1";
string RowGUID = "{" + Guid.NewGuid() + "}";
//add named parameters
cmd.Parameters.AddRange(new OleDbParameter[]
{
new OleDbParameter("#FirstName", FirstName),
new OleDbParameter("#LastName", LastName),
new OleDbParameter("#JobTitleID", JobTitleID),
new OleDbParameter("#SecurityLevel", SecurityLevel),
new OleDbParameter("#RowGUID", RowGUID)
});
int userId = 0;
//Add #EmployeeID to the params collection and then retrieve it with Value
cmd.Parameters.Add("#EmployeeID", OleDbType.Integer).Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
userId = (int)cmd.Parameters["#EmployeeID"].Value;
//userId = (int)cmd.ExecuteScalar();
Console.WriteLine("user created successfully: {0}", deliveryId);
return userId;
}
}
catch (Exception ex)
{
Console.WriteLine("Error: Failed creating the user.\n{0}", ex.Message);
return 0;
}
finally
{
accessConn.Close();
}
}
And when I run the code it throws this error:
System.Data.OleDb.OleDbDataAdapter internal error: invalid parameter accessor: 9 BADBINDINFO
I'm pretty sure the problematic line is this:
cmd.Parameters.Add("#EmployeeID", OleDbType.Integer).Direction = ParameterDirection.Output;
And I just don't get where is the mistake.
If I comment that and the next two lines, and uncomment this:
userId = (int)cmd.ExecuteScalar();
It throws the error: Object reference not set to an instance of an object
Is there a way to get this working with OleDbParameter? So far I'm being forced to make the insert and then a select to get the key generated.
I appreciate any suggestion.
I am hoping someone could check my context of how I am using Transaction with MySql. I believe this should work with the outline below. Can someone look at my code and tell me if I am doing it correctly? Thank you.
I believe this should:
Instantiate the db connection.
Iterate through the DataTable rows of the given DataTable.
Check to see if the table exists and if it does not it will Execute the Create Table.
Execute Insert Command with Parameters of information into the newly created or existing table.
Commit the Transaction and then close the connection.
//Open the SQL Connection
var dbConnection = new MySqlConnection(GetConnectionString(WowDatabase));
dbConnection.Open();
//Instantiate the Command
using (var cmd = new MySqlCommand())
{
//Create a new Transaction
using (var transaction = dbConnection.BeginTransaction())
{
uint lastId = 999999;
for (int i = 0; i < dt.Rows.Count; i++)
{
//var identifier = dt.Rows[i].Field<int>("Identifier");
var id = dt.Rows[i].Field<uint>("Entry");
var name = dt.Rows[i].Field<string>("Name");
var zone = dt.Rows[i].Field<uint>("ZoneID");
var map = dt.Rows[i].Field<uint>("MapID");
var state = dt.Rows[i].Field<Enums.ItemState>("State");
var type = dt.Rows[i].Field<Enums.ObjectType>("Type");
var faction = dt.Rows[i].Field<Enums.FactionType>("Faction");
var x = dt.Rows[i].Field<float>("X");
var y = dt.Rows[i].Field<float>("Y");
var z = dt.Rows[i].Field<float>("Z");
string dataTableName = "entry_" + id;
//Create Table if it does not exist.
if (id != lastId)
{
cmd.CommandText = $"CREATE TABLE IF NOT EXISTS `{dataTableName}` (" +
"`identifier` int NOT NULL AUTO_INCREMENT COMMENT 'Auto Incriment Identifier' ," +
"`zone_id` int NULL COMMENT 'Zone Entry' ," +
"`x_axis` float NULL COMMENT 'X Axis on Map' ," +
"`y_axis` float NULL COMMENT 'Y Axis on Map' ," +
"`z_axis` float NULL COMMENT 'Z Axis on Map' ," +
"`situation` enum('') NULL COMMENT 'Location of the item. Underground, Indoors, Outdoors)' ," +
"`faction` enum('') NULL COMMENT 'Specifies the Faction which can safely access the item.' ," +
"PRIMARY KEY(`identifier`)" +
")";
cmd.ExecuteNonQuery();
lastId = id;
}
//Create command to execute the insertion of Data into desired Table
cmd.CommandText = $"INSERT INTO [{dataTableName}] " +
"([identifier], [zone_id], [x_axis], [y_axis], [z_axis], [situation], [faction], [Create_Date], [Update_Date]) " +
"VALUES (#Identifier, #Zone_Id, #X_Axis, #Y_Axis, #Z_Axis, #Situation, #Faction, #Create_Date, #Update_Date)";
//Add data value with Parameters.
cmd.CommandType = CommandType.Text;
//cmd.Parameters.AddWithValue("#Identifier", identifier);
cmd.Parameters.AddWithValue("#Identifier", id);
cmd.Parameters.AddWithValue("#Zone_Id", zone);
cmd.Parameters.AddWithValue("#X_Axis", x);
cmd.Parameters.AddWithValue("#Y_Axis", y);
cmd.Parameters.AddWithValue("#Z_Axis", z);
cmd.Parameters.AddWithValue("#Situation", state);
cmd.Parameters.AddWithValue("#Faction", faction);
cmd.Parameters.AddWithValue("#Create_Date", DateTime.Now.Date);
cmd.Parameters.AddWithValue("#Update_Date", DateTime.Now.Date);
cmd.ExecuteNonQuery();
} //for (int i = 0; i < dt.Rows.Count; i++)
//Commit the Transaction
transaction.Commit();
} //using (var transaction = dbConnection.BeginTransaction())
} //using (var cmd = new MySqlCommand())
//Close the Connection
dbConnection.Close();
I don't think this will work (as expected) with MySql. There are a few statements that cause an implicit commit - CREATE TABLE is one of them.
http://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html
Consider a using statement
You can actually wrap your existing dbConnection within a using statement to ensure that it is safely disposed of (similar to how you are handling your transactions, commands, etc.) :
//Open the SQL Connection
using(var dbConnection = new MySqlConnection(GetConnectionString(WowDatabase))
{
// Other code omitted for brevity
}
Consistent String Interpolation
You have a few spots where you simply concatenate strings via + but you are mostly taking advantage of C# 6's String Interpolation feature. You might want to consider using it everywhere :
string dataTableName = $"entry_{id}";
No Need for Setting CommandType
Additionally, you could remove the the setting of your CommandType property for your actual cmd object as CommandType.Text is the default :
//cmd.CommandType = CommandType.Text;
In this code every time ShenasehSamapel is two equal values I get an exception that says field ShenasehSamapel is not the primary key:
"The variable name '#ShenasehSamapel' has already been declared.
Variable names must be unique within a query batch or stored
procedure."
Here is the code that generates the error:
private void btnDefineNewKala_Click(object sender, EventArgs e)
{
if (txtShenasehSamapel.Text != "" & txtKalaName.Text != "")
{
//Anbar.FildArray[0]= txtRadif.Text;
Anbar.FildArray [1]= txtShenasehSamapel.Text;
Anbar.FildArray[2] =txtKalaName.Text;
string strDefineKala = "insert into AnbarFava.dbo.DefineKala (ShenasehSamapel ,KalaName )" +
" values ( #ShenasehSamapel , #KalaName )";
//Anbar.AnbarCMD.Parameters.AddWithValue("#Radif", Anbar.FildArray[0]);
Anbar.AnbarCMD.Parameters.AddWithValue("#ShenasehSamapel", Anbar.FildArray[1]);
Anbar.AnbarCMD.Parameters.AddWithValue("#KalaName", Anbar.FildArray[2]);
Anbar.RunQuery(strDefineKala);
for (int Element = 0; Element <= Anbar.FildArray.Length - 1; Element++)
{ Anbar.FildArray[Element] = null; }
//txtRadif.Text = " ";
txtShenasehSamapel.Text = "";
txtKalaName.Text = "";
/**/
string strcmd = "select * from AnbarFava.dbo.DefineKala";
SqlDataAdapter thisDataAdapter = new SqlDataAdapter(strcmd, Anbar.strCNN);
DataTable thisDataTable = new DataTable();
thisDataAdapter.Fill(thisDataTable);
dgvDefineKala.DataSource = thisDataTable;
}
else
{
MessageBox.Show("لطفا تمام خانه ها را پر کنید", "خطا",
MessageBoxButtons.OK); }
}
You are reusing connections and commands across function calls, you have a parameter from a previous call conflicting with your current call.
Anbar.AnbarCMD should not exist, you should create a new command each time. I also assume Anbar also holds a SqlConnection object, it should not be doing that either. All Anbar should hold is a connection string and a new connection and new command should be created each Click (Be sure to put the command and connection inside using statements so they get disposed)
I don't know exactly what RunQuery is doing but it could be rewritten to something similar to
public void RunQuery(string query, params SqlParameter[] parameters)
{
using(var connection = new SqlConnection(_connectionString)
using(var command = new SqlQuery(query, connection)
{
connection.Open();
command.Parameters.AddRange(parameters);
command.ExecuteNonQuery();
}
}
You then call it like so
var param1 = new SqlParameter("#ShenasehSamapel", Anbar.FildArray[1]);
var param2 = new SqlParameter("#KalaName", Anbar.FildArray[2]);
Anbar.RunQuery(strDefineKala, param1, param2);
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");