Auto truncate fields with ODBCDataAdapter on INSERT and UPDATE - c#

I am updating a database using System.Data.Odbc.OdbcDataAdapter. I also don't know what table or fields I'm updating until runtime. The code I have works and is roughly equivalent to the following:
{
mConn = new OdbcConnection(connectionStr);
mConn.Open();
mDataSet = new DataSet();
mDataAdapter = new OdbcDataAdapter(selectStatement, mConn);
mCmdBldr = new OdbcCommandBuilder(mDataAdapter);
var trans = mConn.BeginTransaction();
mDataAdapter.SelectCommand.Transaction = trans;
mDataAdapter.Fill(mDataSet, tableName);
mDataTable = mDataSet.Tables[tableName];
mDataTable.Rows.Add(mNewDataTableRow);
mDataAdapter.Update(mDataSet, tableName);
trans.Commit();
}
The above is stripped down from my actual code, but hopefully gives an idea of how I'm using the DataAdapter. As I say, it works, for the most part...
It does of course fail if I try to insert to many characters into a SQL Server VARCHAR column, in which case I get the following error (in this case, I'm writing to SQL Server, but the database could be something else):
System.Data.Odbc.OdbcException occurred HResult=0x80131937
Message=ERROR [22001] [Microsoft][ODBC SQL Server Driver][SQL
Server]String or binary data would be truncated.
My question is this:
Is there any way in which I can get the OdbcDataAdapter to automatically truncate text fields?
I understand I can turn off ANSI_WARNINGS in the database if I'm using SQL Server, but I might not be, and I don't want to do that anyway because in most cases I would want the above exception to be thrown. I also understand that I can inspect the constraints on the fields myself and truncate the data before I insert it, but I'm looking for something less manual. I'll write that code if I have to, but I'd rather not have to.
I've looked at setting the OdbcParameter.Size property, but this simply throws an exception in a different place. Similarly with DataColumn.MaxLength.
I've also looked at setting DataSet.EnforceConstraints, but that doesn't prevent the above error when actually updating.

Related

Figure out Last_Insert_Id() Using c# and MySql stored Procedure (in Data Access Layer MVC )

I've got an error when i'm using MySql Stored Procedure and
Data Access Layer (MVC)have a method used to read data from database using MySqlDataAdapter and MySqlParameter and DataTable to read data called storedatai was tested this method before in a login controller and it's work as well : the main error here when i need to store last accountId using MySql last_insert_id() function but it always returns null value i tried to Convert it to int then add 1 in every time form opening , but that is useless because it's returns an error
System.ArgumentException: 'Parameter 'accountId' not found in the collection.'
here is the method in Data Access Layer that i use it to store data from database
public DataTable storeData(string trChannel,MySqlParameter[] list_OF)
{
InitializeDb();// Database configration method
MySqlCommand Transmeter = new MySqlCommand
{
CommandType = CommandType.StoredProcedure,
CommandText = trChannel,
Connection = dbcon // dbcon its Connection string comming from DAL
};
if (list_OF != null)
{
Transmeter.Parameters.AddRange(list_OF);
}
MySqlDataAdapter massenger = new MySqlDataAdapter(Transmeter);
DataTable _mainContainer = new DataTable();
massenger.Fill(_mainContainer);
disConnect();
return _mainContainer;
}
The stored procedure that i used it like this after i tried to use last_insert_id() and i failed so i change the sp to this and its work and give me result when i call it inside MySQL Server
CREATE DEFINER=`root`#`localhost` PROCEDURE `getAccountId`(out accountId int(5))BEGIN select Max(acotId)from accounts;set #accountId=last_insert_id(acotId); END
In this case the server going throw an error
Unknown "acotId" in fields list
but i don't need to fix it because it's give me a result , so when i called this procedure inside application using a method that return a DataTable value give the first error that i wrote it before System.ArgumentException: 'Parameter 'accountId' not found in the collection.' for the record i got more than five methods contains the same error most of them with input or output parameter and most of them without ..
public DataTable getAcotId()
{
DataTable pdbContainer = new DataTable();
pdbContainer = _socket.storeData("getAccountId",null);//_socket it's a link to data access layer
return pdbContainer;
}
I tried also method like this with a parameter and it's also didn't works
public DataTable getCusttId()
{
MySqlParameter[] parCut = new MySqlParameter[1];
parCut[0] = new MySqlParameter("?custId", MySqlDbType.Int16, 5) ;
parCut[0].Direction = ParameterDirection.Output;
DataTable pdbContainer = new DataTable();
pdbContainer = _socket.storeData("getCustomerId", parCut);
return pdbContainer;
}
Finally i want to convert the result from this methods to int and i think about using this code
int customerFinalId = getCustId.Rows.Fields[i].Feilds<int>("custId")
That is all guys and i'm dire to need help immediately for more necessary
Thank you a lot for helping me ..
You got MySQL, that is a problem for this problem. It is very common that you need to figure out "the Primary Key of the thing you just inserted". Usually to update the (G)UI.
If this was SQL, the OUTPUT clause would be your friend. This thing alone is worth its memory footprint in gold. But MySQL does not have any equivalent Syntax. That means you have to do it the hard way.
When figuring this value out, it is very important to guard against race conditions. The reliable way is to replace the implicit Transactions and Table locks of the DML statement with a explicit one that covers both the DML statement and the DQL Satement (SELECT) that follows.
Unfortunatley I am not that solid in MySQL Syntax, so somebody else will have to give you exact code.
There are multiple issues with your code
You NEED to provide all the parameters your SP expects or else it will just error out. Since you do not have any try and catch in your SP your entire query will bail on first error.
#accountId is a sql variable and you need to declare that if you want to use it
last_insert_id takes no parameter unless you want to set it explicitly which destroys the whole purpose of it in your example.
The answer here is the second method of getCusttId replacing the ? by #, which works for me.

VFPOleDb schema returned but no results in C#

I'm at the end of my rope on this issue. Trying to connect to a FoxPro directory hosted locally, using the Microsoft OLE DB Provider for Visual FoxPro 9.0 with the following code:
using (var con = new OleDbConnection(#"Data Source=C:\FoxDB;Provider=VFPOLEDB.1;"))
{
con.Open();
using (var cmd = new OleDbCommand("select * from order", con))
{
var dr = cmd.ExecuteReader();
while (dr.Read())
{
Debug.WriteLine(dr["ord_id"]);
}
}
}
Executing the code does not throw an exception, but there are zero rows returned. The schema is discovered and returned, as it has 72 fields present when I examine the data reader (I've done the same with data tables, data sets, data adapters, etc. All return the schema, but zero results).
Building an SSIS package to access the same table and pull into a MSSQL database results in 3,828 records being pulled in. order.dbf on disk is 884kb which seems to jive with the SSIS results I've pulled in.
I've tried adding Collation Sequence to the connection string, both Machine and General to no effect.
Please tell me there's something obvious I'm missing!
UPDATE: So apparently there's something that I just don't understand about FoxPro. If I change the command type to CommandType.TableDirect and switch the command text to just be order, it returns all the rows. Any insight would be appreciated.
I think the problem is not with Foxpro, testing with the same exact code, I can get the result (created a free test table in c:\FoxDb). Ensure that you are using the latest VFPOLEDB driver. It looks like the problem lies within your table.
BTW, order is a keyword, you better write it as:
"select * from [order]"
although it would work as you did (VFP is forgiving in that regard). The problem might also lie in collation sequence you have used (I never use collation sequences other than machine, they are problematic in Turkish, I expect the same in some other languages).

C# Input string was not in correct format for MySQL DateTime

I looking through the various pieces of information about this, and I couldn't find anything about it after an hour of searching, so I've been forced to ask something specifically.
In my MySQL database, I have a series of tables with a Created_dt column, which is a DateTime(6) field. An example of data would be: 2015-06-19 11:52:07.000000
I can pull any column from any table in the database except for this one, for some reason. Whenever I make a connection string, and fill a datatable with the adapter, I get the error in the title. Code:
MySqlCommand cmd = new MySqlCommand("Select Created_dt from comptran_bulk", connection);
MySqlDataAdapter da = new MySqlDataAdapter(cmd as MySqlCommand);
DataTable dt = new DataTable();
da.Fill(dt); // This is where the exception is thrown, when data is loaded into the table.
This command will eventually be replaced with "Select * from view_Sales", and so the solutions to cast it differently I don't think will work. Also, none of the values for Created_dt are Null, so Allow Zero DateTime=True also didn't work.
What would you suggest?
The answer was going in an old error ticket in 2012.
"[1 Jun 2012 13:39] Dan Berger
This does not seem to be fixed in 6.4.5 - I still get the FormatException.
I can narrow the problem down even more if it helps:
MySqlDateTime Success = new MySqlDateTime("2012-01-01 12:00:00");
MySqlDateTime Failure = new MySqlDateTime("2012-01-01 12:00:00.123456"); // throws FormatException
My server is "MySQL 5.1.41-3ubuntu12.10", if that makes a difference."
When using this in C# .NET, the microseconds are the cause of the error. After modifying things to become a datetime(0) instead of datetime(6), things have started to work.

C# - How to tell if DataColumn supports nulls?

I have a datatable that comes from an SQL request. While I am really working against a table using OLEDB, even if I get the table from my SQL server, I have the same problem.
If I fill the datatable and then query the DataColumns - they all say AllowDBNull== true and allowNull == true. But if I look at the table in SSMS, it states otherwise.
string selectStmt= "Select * from foobar; "
DataSet NewData = new DataSet();
using (SqlConnection DataConn = new SqlConnection(MyConnectionString))
{
SqlDataAdapter DataAdapter = new SqlDataAdapter(selectStmt, DataConn );
var Results = DataAdapter.Fill(NewData, tableName);
}
DataColumn Col = NewData.Tables[0].Columns[0];
// Col.AllowDBNull is always true as is Col.AllowNull
I also can't seem to figure out where to get the length of a string field.
This makes it a little difficult to implement some simple client side error checking before I try to upload data.
If I were only dealing with SQL server based tables, I could use Microsoft.SqlServer.Management.Sdk and Microsoft.SqlServer.Management.Smo. Since I am not, that's out.
Try
var Results = DataAdapter.FillSchema(NewData, SchemaType.Source, tableName);
See if that gives you the level of schema detail you need.
A ResultSet isn't going to know column schema data like that, it would be too intensive an operation to do that per command execution, instead the runtime will create schema information on the fly only using the data it gets back in the data/result-set. For full blown schema you'd have to use something like EF or code the schema yourself. The only thing you can rely on for runtime schema's is the data type (unless the data columns were specifically coded with their attributes).
To properly test for DbNull you do this:
if ( dataRow[colNameOrIndex].Value == DbNull.Value){
//null
}

c# System.Data.SQLite parameters error

I am using SQlite database on C# and have an error issue with parameters.
using System.Data.SQLite;
Here is a main code part:
this.dbUpdateCommand = new SQLiteCommand();
dbUpdateCommand.Parameters.AddWithValue("#paramNewValue", (string)this.valueNew);
dbUpdateCommand.Parameters.AddWithValue("#paramPredValue", (string)this.valuePred);
dbUpdateCommand.Parameters.AddWithValue("#paramTableName", (string) this.tableName);
dbUpdateCommand.Parameters.AddWithValue("#paramColumnName", (string)this.columnInDB);
dbUpdateCommand.Parameters.AddWithValue("#paramKeyField", (string)this.keyFieldInDB);
dbUpdateCommand.Parameters.AddWithValue("#paramKeyValue", (string)this.keyValueInDB);
dbUpdateCommand.CommandText = "UPDATE #paramTableName SET #paramColumnName=#paramNewValue WHERE #paramKeyField=#paramKeyValue;";
dbUpdateCommand.ExecuteNonQuery();
And it throws me exception "SQLite error near "#paramTableName": syntax error"
I tried to make pure SQL statement without params but with strings concatenation and it works with the same variables (this.tableName is valid db tablename)
So it seems something wrong with my parameters. Does anybody knows, what?
You can't use parameters to reference objects (tables & columns). You would need to drop the actual table and column names into your query. Be careful of SQL injection while doing so.

Categories