Ticket Hash: | 4bbf851fa5b26c1ca74a102731942f99ba8aa18e | |||
Title: | DBConcurrencyException | |||
Status: | Closed | Type: | Incident | |
Severity: | Important | Priority: | Medium | |
Subsystem: | Db_Type_Conversion | Resolution: | Not_A_Bug | |
Last Modified: | 2012-02-29 14:54:09 | |||
Version Found In: | 1.0.79.0 | |||
Description: | ||||
DBConcurrencyException
This issue is related to the closed ticket [343d392b51] In fact the problem still remains. Please read the old ticket first. As a workaround I now do not use adapter.Update() any longer (as it raises the exception). Instead of String table = “table”; try { sql = "select * from table where ..."; da = new SQLiteDataAdapter(sql, db_con); da.Fill(ds, table); dt = ds.Tables[table]; … manipulate_data(); int i = da.Update(dt); // here the DBConcurrencyException raises !!! I now use a stupid sql.command in a loop. … String sql = String.Format("update table set … “ SQLiteCommand cmd = new SQLiteCommand(sql, dbconnection); return cmd.ExecuteNonQuery(); … This works, but it does not perform well and it is very ugly code. ________________________________ The DBConcurrencyException raises not on every adapter.Update() statement. Sometimes it works, sometimes not. Sometimes a few records are updated, sometimes just only one, sometimes none. Sometimes it raises on this table, sometimes on the other table. All my tables have as a first column a DateTime column (“CHANGE_DATE”). It does not matter whether I do row[“CHANGE_DATE”] = DateTime.Now; Or row["CHANGE_DATE"] = DateTime.Now.Year + "-" + DateTime.Now.Month + "-" + DateTime.Now.Day + " " + DateTime.Now.TimeOfDay; regards, Simon mistachkin added on 2011-12-25 23:31:09 UTC: anonymous added on 2011-12-26 23:23:14 UTC: xydatetime = reader.GetDateTime(0); raises an exception: TypeInitialisationException: wrong format _______ String sql = "select CHANGE_DATE, ... from TABLE .. "; SQLiteCommand cmd = new SQLiteCommand(sql, dbconnection); SQLiteDataReader reader = cmd.ExecuteReader(); if (reader.HasRows) while (reader.Read()) { ... xydatetime = reader.GetDateTime(0); ... } reader.Close(); mistachkin added on 2011-12-27 03:24:15 UTC: anonymous added on 2011-12-27 17:54:42 UTC: the following code raises System.FormatException: String Sql = "Select CHANGE_DATE, … from table ..”; da = new SQLiteDataAdapter(sql, dbconnection); da.Fill(dset, table); The column CHANGE_DATE is of type DATETIME. anonymous added on 2011-12-28 00:06:25 UTC: mistachkin added on 2011-12-28 05:07:57 UTC: anonymous added on 2011-12-28 09:43:43 UTC: mistachkin added on 2011-12-29 01:43:17 UTC: anonymous added on 2012-01-14 00:01:19 UTC: I tried: first version connectionstring: DateTimeFormat= JulianDay table product: change_date datetime, price number, name varchar2, id integer firstly, I did: update product set change_date = 2455928.0 //which is 2012-01-01 12:00:00 then: sql = “select change_date, id, name, price from product”; adapter = new SQLiteDataAdapter(sql, db_con); adapter.Fill(ds, datatab); …. row[“price”] += 1; row[“change_date”] = DateTime.Now; …. adapter.update(datatab); <- here the DBConcurrencyException raises _______________________________________________ second version: same table; connectionString: DateTimeFormat= JulianDay update product set change_date = 2455928.0 //which is 2012-01-01 12:00:00 then !! difference !! sql = “select julianday(change_date) as change_date, id, name, price from product”; adapter = new SQLiteDataAdapter(sql, db_con); adapter.Fill(ds, datatab); …. row[“price”] += 1.0; // in fact now the column is of type System.Double row[“change_date”] = (double)row[“change_date”] + 1.0; …. adapter.update(datatab); no exception raises, but what happens is: the price column is updated, the DateTime-Column is not ! What's wrong ? mistachkin added on 2012-01-14 03:00:45 UTC: Instead of: row["change_date"] = DateTime.Now; Try: row["change_date"] = SQLiteConvert.ToJulianDay(DateTime.Now); anonymous added on 2012-01-14 14:27:33 UTC: => compiler says: An object reference is required for the non-static field, method, or property 'System.Data.SQLite.SQLiteConvert.ToJulianDay(System.DateTime)' mistachkin added on 2012-01-15 01:01:22 UTC: mistachkin added on 2012-01-15 01:28:17 UTC: anonymous added on 2012-01-15 19:04:07 UTC: update product set change_date = 2455928.0 // which is 2012-01-01 12:00:00 change_date is of type DateTime ! ---------------- sql = “select change_date, price, ....”; adapter = new SQLiteDataAdapter(sql, db_con); adapter.Fill(ds, datatab); …. row[[price]] += 1; row[[change_date]] = SQLiteConvert.ToJulianDay(DateTime.Now); <- TypeConverionException raises, which is clear, because: the original SQLite table-column is of type DateTime, then the ADO-table is also of type System.DateTime, to which we want to assign a double. System.ArgumentException: invalid type conversion "Double" to "DateTime".<2455941,93204139> cannot be saved to CHANGE_DATE column. Expected type: DateTime. ---> System.InvalidCastException: invalid conversion "Double" to "DateTime". mistachkin added on 2012-01-16 01:00:09 UTC: row["change_date"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.FFFFFFFK"); anonymous added on 2012-01-18 21:07:58 UTC: I now use DateTimeFormat=JulianDay as you recommended. I converted the data to floats as described: update product set change_date = 2455928.0 // which is 2012-01-01 12:00:00 I now use: row["change_date"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.FFFFFFFK"); but the DBConcurrencyException still raises (not everytime, but most often) anonymous added on 2012-02-03 06:56:17 UTC: mistachkin added on 2012-02-03 13:46:16 UTC: anonymous added on 2012-02-05 23:02:43 UTC: e.Source: System.Data e.Data: System.Collections.ListDictionaryInternal e.StackTrace: at System.Data.Common.DbDataAdapter.UpdatedRowStatusErrors(RowUpdatedEventArgs rowUpdatedEvent, BatchCommandInfo[] batchCommands, Int32 commandCount) at System.Data.Common.DbDataAdapter.UpdatedRowStatus(RowUpdatedEventArgs rowUpdatedEvent, BatchCommandInfo[] batchCommands, Int32 commandCount) at System.Data.Common.DbDataAdapter.Update(DataRow[] dataRows, DataTableMapping tableMapping) at System.Data.Common.DbDataAdapter.UpdateFromDataTable(DataTable dataTable, DataTableMapping tableMapping) at System.Data.Common.DbDataAdapter.Update(DataTable dataTable) at Test.mytest.mytest.UpdateTest(DataTable dt) in C:\Users\admin\Documents\Visual Studio 2008\Projects\Test\Test\mytest\mytest.cs:Line 236. e.TargetSite: Int32 UpdatedRowStatusErrors(System.Data.Common.RowUpdatedEventArgs, BatchCommandInfo[], Int32) e.Message: Concurrency violation: the UpdateCommand affected 0 of the expected 1 records. mistachkin added on 2012-02-06 22:01:43 UTC: anonymous added on 2012-02-08 13:42:08 UTC: trace output: ... Prepare: 123241624 SQLite message (0): Preparing {UPDATE [main].[PRODUCT] SET [CHANGE_DATE] = @param1, [ID] = @param2, [PRICE] = @param3 WHERE (([CHANGE_DATE] = @param4) AND ([ID] = @param5) AND ((@param6 = 1 AND [PRICE] IS NULL) OR ([PRICE] = @param7)))}... Prepare: 123239424 'Test.vshost.exe' (Managed): Loaded 'C:\Windows\assembly\GAC_MSIL\System.Data.resources\2.0.0.0_de_b77a5c561934e089\System.Data.resources.dll' A first chance exception of type 'System.Data.DBConcurrencyException' occurred in System.Data.dll ... mistachkin added on 2012-02-08 21:13:05 UTC: anonymous added on 2012-02-09 23:19:57 UTC: code: cstr = new SQLiteConnectionStringBuilder(); cstr.DataSource = myDB; cstr.Version = 3; cstr.DateTimeKind = DateTimeKind.Local; cstr.DateTimeFormat = SQLiteDateFormats.JulianDay; cstr.Flags = SQLiteConnectionFlags.LogPrepare; ... for (int i = 0; i < rcount; i++) { System.Threading.Thread.Sleep(5000); dt.Rows[i]["PRICE"] = (double)dt.Rows[i]["PRICE"] + 5.123; string s = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.FFFFFFFK"); dt.Rows[i]["CHANGE_DATE"] = s; } --- adapter.Update(); string s outputs: 2012-02-09 23:51:24.746+01:00 2012-02-09 23:51:29.756+01:00 2012-02-09 23:51:34.762+01:00 2012-02-09 23:51:39.772+01:00 2012-02-09 23:51:44.777+01:00 2012-02-09 23:51:49.787+01:00 2012-02-09 23:51:54.797+01:00 2012-02-09 23:51:59.807+01:00 2012-02-09 23:52:04.817+01:00 2012-02-09 23:52:09.823+01:00 2012-02-09 23:52:14.829+01:00 2012-02-09 23:52:19.835+01:00 and so on mistachkin added on 2012-02-10 06:55:38 UTC: runTest {test tkt-4bbf851fa5-1.1 {SQLiteDataAdapter update fail} -setup { setupDb [set fileName tkt-4bbf851fa5-1.1.db] } -body { set id [object invoke Interpreter.GetActive NextId] set dataSource [file join [getDatabaseDirectory] $fileName] set sql(inserts) "" set sql(1) [subst { \ CREATE TABLE t1(y DATETIME PRIMARY KEY, z FLOAT); \ [for {set i 1} {$i < 10} {incr i} { append sql(inserts) [appendArgs \ "INSERT INTO t1 (y, z) VALUES(JULIANDAY('" \ [clock format $i -format [getDateTimeFormat]] "'), " $i "); "] }; return [expr {[info exists sql(inserts)] ? $sql(inserts) : ""}]] \ }] set sql(2) [subst { \ SELECT y, z FROM t1 ORDER BY y; \ }] unset -nocomplain results errors set code [compileCSharpWith [subst { using System; using System.Data; using System.Data.SQLite; namespace _Dynamic${id} { public class Test${id} { public static void Main() { SQLiteConnectionStringBuilder connStr = new SQLiteConnectionStringBuilder(); connStr.DataSource = "${dataSource}"; connStr.Version = 3; connStr.DateTimeKind = DateTimeKind.Local; connStr.DateTimeFormat = SQLiteDateFormats.JulianDay; connStr.Flags = SQLiteConnectionFlags.LogPrepare; using (SQLiteConnection connection = new SQLiteConnection( connStr.ToString())) { connection.Open(); using (SQLiteCommand command = connection.CreateCommand()) { command.CommandText = "${sql(1)}"; command.ExecuteNonQuery(); } using (SQLiteDataAdapter dataAdapter = new SQLiteDataAdapter( "${sql(2)}", connection)) { using (DataSet dataSet = new DataSet()) { dataAdapter.Fill(dataSet, "t1"); DataTable dataTable = dataSet.Tables\["t1"\]; dataTable.Columns\["y"\].Unique = true; dataTable.PrimaryKey = new DataColumn\[\] { dataTable.Columns\["y"\] }; [expr {[isMono] ? "#pragma warning disable 219" : ""}] SQLiteCommandBuilder commandBuilder = new SQLiteCommandBuilder(dataAdapter); [expr {[isMono] ? "#pragma warning restore 219" : ""}] for (int index = 0; index < dataTable.Rows.Count - 1; index++) { System.Threading.Thread.Sleep(1000); dataTable.Rows\[index\]\["y"\] = DateTime.Now.ToString("[getDateTimeFormat]"); dataTable.Rows\[index\]\["z"\] = (double)dataTable.Rows\[index\]\["z"\] + 1.123; } dataAdapter.Update(dataTable); // DBConcurrencyException (?) } } } } } } }] true true true results errors System.Data.SQLite.dll] list $code $results \ [expr {[info exists errors] ? $errors : ""}] \ [expr {$code eq "Ok" ? [catch { object invoke _Dynamic${id}.Test${id} Main } result] : [set result ""]}] $result } -cleanup { cleanupDb $fileName unset -nocomplain result code results errors sql dataSource id db fileName } -constraints \ {eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -match \ regexp -result {^Ok System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 \{\}$}} mistachkin added on 2012-02-10 19:13:56 UTC: anonymous added on 2012-02-14 07:33:46 UTC: mistachkin added on 2012-02-14 09:59:01 UTC: anonymous added on 2012-02-14 11:47:02 UTC: db-file: http://dl.dropbox.com/u/62206335/xy.db3 code: http://dl.dropbox.com/u/62206335/code.txt I found another strange behaviour: the test code likes to override the price with the value 5.123. the first ten rows are updated but with the value 5, not 5.123. Then the exception occurs. (it's the same code i've sent by email) mistachkin added on 2012-02-14 21:47:05 UTC: mistachkin added on 2012-02-14 22:14:23 UTC: It appears the mixture of data in the database combined with the NUMBER column type is the root cause of the issue. For example, try this query with your database: SELECT typeof(PRICE) FROM product; Notice that some of the results say "integer" and others "real". For SQLite, this is not a big deal, since it will simply default the column affinity to TEXT; however, System.Data.SQLite uses the column type information to provide a mapping to the actual .NET type and database column type. In the case of "NUMBER", it returns the default, DbType.Object. At that point, I think .NET attempts to figure out the type of the column based on the data currently in it for the row (this is just an educated guess) and then attempts to convert the new value to that type. If the new value ends up being truncated from REAL to INTEGER, for example, it could result in 5.123 becoming 5, as you stated. This may cause the exception, for example, if the value was actually 5 to start with. mistachkin added on 2012-02-14 22:21:31 UTC: anonymous added on 2012-02-15 07:01:55 UTC: and just for your information: you also closed ticket [d76b409d07] which was not my ticket. (and this guy uses only varchars and one integer prim key, seems that my problem is not his problem) Simon mistachkin added on 2012-02-15 07:56:04 UTC: anonymous added on 2012-02-18 11:13:37 UTC: I started with a complete new db-file, created a table product with one Datetime column, one integer prim key column and then only text and real columns. Again I inserted my 180 products. after round about ten runs of my program with each updates round about 30 rows correctly with no problems the exception ocurrs again, having updated only 15 rows. running the given code with the given dbfile will update again only 15 rows before the exception occurs. http://dl.dropbox.com/u/62206335/code2.txt http://dl.dropbox.com/u/62206335/code2.txt anonymous added on 2012-02-18 16:31:33 UTC: http://dl.dropbox.com/u/62206335/code2.txt http://dl.dropbox.com/u/62206335/abc.db3 mistachkin added on 2012-02-19 12:10:11 UTC: UPDATE [main].[t1] SET [y] = @param1, [z] = @param2 WHERE (([x] = @param3) AND ([y] = @param4) AND ([z] = @param5)) And the values for the parameters are as follows: @param1 = 2455976.6870139237 (double) @param2 = 9.876 (double) @param3 = 1 (long) @param4 = 2455975.9869903936 (double) @param5 = 5.123 (double) The problem is that the actual first row in the table contains this data: INSERT INTO t1 (x, y, z) VALUES(1, 2455975.98699039, 5.123); This causes the WHERE clause in the above UPDATE query to match zero rows because 2455975.98699039 (in database) is not equal to 2455975.9869903936 (query parameter). anonymous added on 2012-02-19 22:42:13 UTC: mistachkin added on 2012-02-20 00:13:42 UTC: The "extra" digits are presumably caused by double precision rounding errors, see: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html anonymous added on 2012-02-20 00:28:39 UTC: but what I don't understand is the cause for the exception. If the where clause does not match, ok, so what, the row will not be updated. But why the exception ? mistachkin added on 2012-02-20 04:10:09 UTC: |