Short background: I am replacing an outdated, Visual Based based program with a C#-based one. With the program comes an Access (JET) based database which is already in use. For now, I want to connect to the current database for practical reasons. However in the foreseeable future I'd like to replace it with SQL Server.
Question: The database stores financial information using the Access 'Currency' datatype. In C#, I use 'Decimal' to represent financial information. Naturally, I get an error when I try an INSERT or UPDATE-query to store the Decimal in the Currency-field (actually, I get an error once and with it, it automatically changes the datatype of that specific record to Decimal). I'm not sure what the best way to solve this problem is:
Transform the Decimal into Currency in my program and inserting it after. Is this even possible (C# says the values from the field are of the DBNull-type since it doesn't know Currency)? If yes, how do I do this?
Change the datatype of the field into Decimal. Will I risk corrupting financial information when I do this?
Any other/better suggestions?
Thanks in advance!
The exact error message:
System.Data.Odbc.OdbcException (0x80131937): ERROR [07006]
[Microsoft][ODBC Microsoft Access-stuurprogramma]Inbreuk op kenmerk van beperkt gegevenstype
It's Dutch and translates to Restricted data type attribute violation
My UPDATE code:
public Boolean setFuelCosts(int rentID, Decimal fuelcosts)
{
string conString = lem2;
string queryString = "UPDATE rental SET fuel = ? WHERE rentid = ?";
OdbcCommand command = new OdbcCommand(queryString);
command.Parameters.Add("#fuel", OdbcType.Decimal).Value = fuelcosts;
command.Parameters.Add("#rentid", OdbcType.Int).Value = rentID;
return factory.executeUpdateCommand(conString, command);
}
public Boolean executeUpdateCommand(String conString, OdbcCommand command)
{
bool result = false;
using (OdbcConnection connection = new OdbcConnection(conString))
{
try
{
command.Connection = connection;
command.CommandType = CommandType.Text;
connection.Open();
int i = command.ExecuteNonQuery();
result = (i >= 1);
connection.Close();
}
catch (Exception exc)
{
System.Windows.Forms.MessageBox.Show(exc.Message);
System.Windows.Forms.MessageBox.Show(exc.StackTrace);
}
}
return result;
}
Your issue appears to be a limitation of the Access ODBC driver when dealing with Currency fields using System.Data.Odbc in .NET. An OdbcDataReader will return those fields as System.Decimal (if the value is not NULL), but System.Data.Odbc apparently won't accept a System.Decimal parameter for a Currency field.
As a workaround you could replace
command.Parameters.Add("#fuel", OdbcType.Decimal).Value = fuelcosts;
with
command.Parameters.Add("#fuel", OdbcType.NVarChar).Value = fuelcosts.ToString("0.0000");
I just tested this from C# 2010 against an Access 2000 database file and it worked for me.
Related
I'm creating a basic customer inventory application, and when converting the code from using SQL Server to using MS Access (which I'm quite a bit less versed in), I ran into a "Data type mismatch" error when trying to do a basic insert.
I've looked into several similar questions here, and double checked the msdn syntax guide, but I can't find a reason why the script I've written would generate that error. I changed my code several times to try and ensure proper data type (ending up with what I have below with explicit typing and adding the value later). I've actually even taken the string and pasted it into MS Access (sans white space and double quotes), and it seems to work just fine with the values given. At this point, I'm really and truly stumped, and I'm wondering if it might just be a quirk with the Oledb adapter? Any help would be appreciated. Thanks.
// SQL query defined elsewhere:
public static readonly string sqlAddCustomerNotes = "INSERT INTO CustomerNotes (Customer_ID, Notes, NotesDate) "
+ "VALUES(#Customer_ID, #Notes, #NotesDate);";
// end sql query
// data access function
public static void addNotes(int customerID, string notes, DateTime notesDate)
{
string query = Scripts.sqlAddCustomerNotes;
using (
OleDbCommand dbCommand = new OleDbCommand()
{
Connection = new OleDbConnection(ConnectionAccess.connString),
CommandType = CommandType.Text,
CommandText = query,
Parameters =
{
new OleDbParameter("#Customer_ID", OleDbType.Integer),
new OleDbParameter("#Notes", OleDbType.LongVarChar),
new OleDbParameter("#NotesDate", OleDbType.DBTimeStamp)
}
}) // end using parenthetical
{ // begin using scope
dbCommand.Parameters[0].Value = customerID;
dbCommand.Parameters[1].Value = notes;
dbCommand.Parameters[2].Value = notesDate;
foreach (OleDbParameter param in dbCommand.Parameters)
{ // replace ambiguous null values with explicit DBNulls.
if (param.Value == null)
{
param.Value = DBNull.Value;
}
}
dbCommand.Connection.Open();
int rowsAffected = dbCommand.ExecuteNonQuery();
dbCommand.Connection.Close();
Console.WriteLine($"Rows affected: {rowsAffected}");
}
} // end addCustomerNotes
/*
table "CustomerNotes" has the following columns:datatypes
CustomerNotes_ID: AutoNumber
Customer_ID: Number
Notes: Memo
NotesDate: Date/Time
CreateDate: Date/Time
test case (in code) was:
#Customer_ID = 5
#Notes = "customer might change last name to simpson."
#NotesDate = {6/26/2019 12:05:39 PM}
*/
It probably is a date, not a timestamp:
new OleDbParameter("#NotesDate", OleDbType.DBDate)
Considering June7's comment about delimiters, it seems the issue lies in some issue inherent to the OleDbParameter type. In SQL Server terms, I do want DateTime (not Date), but representing it as a DBTimeStamp seems to make it unrecognizable by Access.
For the time being, I've sent the date as a VarChar and allowed Access to convert it however its internal engine sees fit. It feels/seems wrong, but it does, in fact, solve the problem.
Parameters =
{
new OleDbParameter("#Customer_ID", OleDbType.Integer),
new OleDbParameter("#Notes", OleDbType.LongVarChar),
new OleDbParameter("#NotesDate", OleDbType.VarChar)
}
EDIT: Just saw June7's latest comment, and there was in fact, an answer in another thread. OleDbType.DBDate doesn't do what I want, but OleDbType.Date does.
I am trying to add some record to ACCESS file ,as you can see here :
string strconnection = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=AccessTemp.mdb";
private void InsertSellItems(List<TTMSModel> lstttms )
{
try
{
foreach (TTMSModel t in lstttms)
{
if (t.TypeMember == "حقیقی") t.TypeMember = "1";
else
{
t.TypeMember = "2";
}
OleDbConnection objconnection = new OleDbConnection(strconnection);
OleDbCommand objcommand = new OleDbCommand("INSERT INTO Foroush_Detail" +
"(KalaKhadamatName,KalaCode,BargashtType,Price,MaliatArzeshAfzoodeh,AvarezArzeshAfzoodeh,HCKharidarTypeCode,KharidarPostCode,KharidarPerCityCode,KharidarTell,KharidarAddress,KharidarName,KharidarLastNameSherkatName,KharidarEconomicNO,KharidarNationalCode,HCKharidarType1Code,CityCode,stateCode,IsSent,Sarjam)" +
"VALUES('فروش'," +"'0'"+",'0','"+t.PriceAmount+"','"+t.MayorAmount+"','"+t.TaxAmount+"','"+t.TypeMember+"','"+t.ZipCode+"','"+t.City+"','"+t.PhoneNumber+"','"+t.Address+"','"+t.Name+"','"+t.Name+"','"+t.EconomicNumber+"','"+t.IntNumber+"','2','"+t.City+"','"+t.Province+"','0','0')",
objconnection);
objconnection.Open();
objcommand.ExecuteNonQuery();
objconnection.Close();
}
}
catch (OleDbException a)
{
MessageBox.Show(a.Message);
}
}
I fetched the data from SQL server 2012.but after executing this query i got this error:
the field is too small to accept the amount of data you attempted to add access 2010.
The table structure is like this :
Best regards
For BargashtType column that is declared as Yes/No type, you are trying to insert فروش .Which is invalid, as the field will accept only 0 or 1 i.e. true or false.
It appears to me you are passing ever value in the query as a string, depite the fact some of the fields are numbers:
'"+t.City+"','"+t.Province+"'
Both of these values have a single quote around them, meaning they are strings, yet the two fields are Numbers.
That means you're leaving Access to do the conversion, you might want to try passing them as numeric values and see if that resolves the problem
I'm connecting to a DB2 database using the OdbcConnection using C#. I'm connecting, making queries, etc. and all is going well until I query for a field of which the data type is XML. I get an error back stating Unknown SQL type - -370. I've found restrictions with the .NET ODBC driver on LOB fields (here) but the error codes are -98 (LOB), -99 (CLOB) and -350 (DBCLOB). There is a workaround suggesting I add LONGDATACOMPAT=1 to my connectionstring but this is not working for -370. Does anyone know how I can get past this issue?
With XMLSERIALIZE in the query and LONGDATACOMPAT=1 in the connection string (as mentioned above), I was able to get large (>100KB) XML from fields using the CLOB data type. Something like this worked for me:
var command = connection.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText =
"SELECT XMLSERIALIZE(xmlfield AS CLOB(10M)) AS xmlfield FROM [table] WHERE [condition]";
using (command)
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
var foo = !reader.IsDBNull(0) ? reader.GetString(0) : null;
//do stuff...
}
}
}
I've set the maximum CLOB size to 10 megabytes, which is a safe ceiling for my project. See IBM's page on XMLSERIALIZE for more info.
mustaccio's link (here) provided the solution.
I set my table column as integer.
Now I am trying to read it in my c# code using getint32 and for some reason I get a cast error, and when I checked some more I saw that I am getting a decimal from my db. how can that be? Isn't the oracle integer equals to c# int?
using (OracleCommand cmd = new OracleCommand(#"select id,title from table"))
{
cmd.Connection = _conn;
OracleDataReader r = cmd.ExecuteReader();
while (r.Read())
{
Debug.WriteLine(reader.GetFieldType(0)); // <--decimal
//reader.GetDecimal(0);
reader.GetInt32(0); <---cast error
Debugger.Break();
}
r.Close();
}
the id column is set as integer, also tryed number. comfused :S
Have a read at this:
Which .NET data type is best for mapping the NUMBER Oracle data type in NHibernate?
Oracle number maps to .net decimal. Microsoft is aware of this issue.
You shouldn't do that.
An int (System.Int32) is not big enough to hold every possible decimal value. If your column type is decimal, use GetDecimal() method, if your column type is int, use GetInt32() method.
There is no implicitly conversation decimal to int at all.
I have a .NET Wndows application in C#. It's a simple Windows application that is using the MySql 5.1 database community edition. I've downloaded the MySql ODBC driver and have created a dsn to my database on my local machine. On my application, I can perform get type queries without problems, but when I execute a given insert statement (not that I've tried doing any others), I get the following error:
{"ERROR [HY001] [MySQL][ODBC 5.1 Driver][mysqld-5.0.27-community-nt]Memory allocation error"}
I'm running on a Windows XP machine. My machine has 1 GB of memory.
Anyone have any ideas? See code below
OdbcConnection MyConn = DBConnection.getDBConnection();
int result = -1;
try
{
MyConn.Open();
OdbcCommand myCmd = new OdbcCommand();
myCmd.Connection = MyConn;
myCmd.CommandType = CommandType.Text;
OdbcParameter userName = new OdbcParameter("#UserName", u.UserName);
OdbcParameter password = new OdbcParameter("#Password", u.Password);
OdbcParameter firstName = new OdbcParameter("#FirstName", u.FirstName);
OdbcParameter LastName = new OdbcParameter("#LastName", u.LastName);
OdbcParameter sex = new OdbcParameter("#sex", u.Sex);
myCmd.Parameters.Add(userName);
myCmd.Parameters.Add(password);
myCmd.Parameters.Add(firstName);
myCmd.Parameters.Add(LastName);
myCmd.Parameters.Add(sex);
myCmd.CommandText = mySqlQueries.insertChatUser;
result = myCmd.ExecuteNonQuery();
}
catch (Exception e)
{
//{"ERROR [HY001] [MySQL][ODBC 5.1 Driver][mysqld-5.0.27-community-nt]Memory
// allocation error"} EXCEPTION ALWAYS THROWN HERE
}
finally
{
try
{
if (MyConn != null) MyConn.Close();
}
finally { }
}
It was because some fields accept null, I had passed them as null where they should be passed as DBNull.Value. For all the fields which allow null should be checked for null and if found null, DBNull.Value should be passed.
Just for the sake of completeness, Chinjoo's SQL statement would likely be something like this:
mySqlQueries.insertChatUser = "insert into ChatUsers (UserName, Password, FirstName, LastName, sex) values (?,?,?,?,?);";
This is known as a parameterized insert where each question mark represents one of his parameters. In this simple example the order of the parameters in the parameter collection in code must match the order of the column names in the SQL statement.
While less elegant than using a function, the fix for his null problem would look something like this for one of his parameters:
OdbcParameter LastName = new OdbcParameter("#LastName", u.LastName);
is replaced with
// if the value is "null" return DBNull, else just the value
OdbcParameter LastName = new OdbcParameter("#LastName",
(u.LastName == null) ? System.DBNull.Value : (object)u.LastName);
At least in my code (which is slightly different) the inner cast to type object is required since otherwise the compiler isn't sure what type the ?: operator should return.
Hope this helps anyone who is relatively new to parameterization, etc.
No criticism of Chinjoo implied at all--his posting helped me out! Just thought I'd share for the less-experienced. I'm by no means expert so take everything I say with a grain of salt.
This exception also can be raised if you try to insert invalid chars in a VARCHAR field. In example, if the string is generated by a UNIX machine and has end of line characters '\n'. You can just replace that problematic characters to Windows style, or viceversa, or just delete it if you don't want to store end of lines.
You can check the strings, and if any of them has end of line characters, try to repeat the insert deleting them. If it works, the problem are these characters.