SQL DBGeography second insert fails - c#

This one is a strange one. I am trying to save a polygon from Google maps into MS SQL, via an MVC controller. The problem is that the first time I do it, it works, the second time it gives me the error:
The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Parameter 3 ("#2"): The supplied value is not a valid instance of data type geography. Check the source data for invalid values. An example of an invalid value is data of numeric type with scale greater than precision.
I am using EntityFramework 6.1.3, code first. The error appears on the commit line below:
var newPoly = new GenericPolygon()
{
Name = webShape.Name,
PolyShape = shapePolygon,
IsEnabled = true,
IsDeleted = false
};
_unitOfWork.PolygonRepository.Add(newPoly);
_unitOfWork.Commit();
The SQL table structure is the same as the class except that it has an int ID identity column as well, and the name is a varchar(255). The PolyShape column is of type geography.
The shapePolygon variable is defined like this, with the class adding a read-only property called "LongLat", which is used to switch from the Google LatLong to the MS LongLat format:
var shapePolygon = DbGeography.PolygonFromText("POLYGON((" + webShape.LongLat + "))", 4326);
The commit line itself calls the db context save method (I'm using UoW pattern to cut down on code):
this.context.SaveChanges();
I can't for the life of me figure out why it works once, and then not again, unless I restart my VS (running VS 2013 with IIS Express - SQL 2008 R2 Enterprise on a server).
Any help or pointers would be appreciated :-)

I seem to have narrowed down on the issue, and whilst it is more of a workaround than an answer this may help someone else.
The issue is the version of SQL Server, namely SQL 2008 R2 10.50.4000. I migrated my database to SQL Server 2012 build 11.0.5058, after which the code worked, every time.
Hope this helps someone!

I just had this and solved it by reversing the points in the polygon. Apparently SQL Server is left handed with these things or something.
So instead of having a string concatenation like strGeog += string.Format("{0} {1}, ", latlong[0], latlong[1]); I changed it to:
foreach (XmlNode xnPoly in xmlPolyList)
{
strGeog = "";
firstlatlong = null;
if (xnPoly["coordinates"] != null)
{
latlongpairs = xnPoly["coordinates"].InnerText.Replace("\n", "").Split(' ');
foreach (string ll in latlongpairs)
{
latlong = ll.Split(',');
if (firstlatlong == null) firstlatlong = latlong;
strGeog = string.Format("{0} {1}, ", latlong[0], latlong[1]) + strGeog;
}
}
if (strGMPoly.Length > 0)
{
strGeog = strGeog.Substring(0, strGeog.Length - 2); //trim off the last comma and space
strGeog = "POLYGON((" + string.Format("{0} {1} ", firstlatlong[0], firstlatlong[1]) + strGeog + "))"; // conversion from WKT needs it to come back to the first point.
}
i++;
dbPCPoly = new PostCodePolygon();
dbPCPoly.geog = DbGeography.PolygonFromText(strGeog, 4326);
LocDB.PostCodePolygons.Add(dbPCPoly);
LocDB.SaveChanges();
Console.WriteLine(string.Format("Added Polygon {0} for Postcode ({1})", dbPCPoly.PCPolyID, dbPC.PostCodeName));
}

Related

Troubleshooting "Data type mismatch in criteria expression." during MS Access Insert.Into

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.

Error from SQL query

Currently I'm working on cleaning up some code on the backend of an application I'm contracted for maintenance to. I ran across a method where a call is being made to the DB via Oracle Data Reader. After examining the SQL, I realized it was not necessary to make the call to open up Oracle Data Reader seeing how the object being loaded up was already within the Context of our Entity Framework. I changed the code to follow use of the Entity Model instead. Below are the changes I made.
Original code
var POCs = new List<TBLPOC>();
Context.Database.Connection.Open();
var cmd = (OracleCommand)Context.Database.Connection.CreateCommand();
OracleDataReader reader;
var SQL = string.Empty;
if (IsAssociate == 0)
SQL = #"SELECT tblPOC.cntPOC,INITCAP(strLastName),INITCAP(strFirstName)
FROM tblPOC,tblParcelToPOC
WHERE tblParcelToPOC.cntPOC = tblPOC.cntPOC AND
tblParcelToPOC.cntAsOf = 0 AND
tblParcelToPOC.cntParcel = " + cntParcel + " ORDER BY INITCAP(strLastName)";
else
SQL = #"SELECT cntPOC,INITCAP(strLastName),INITCAP(strFirstName)
FROM tblPOC
WHERE tblPOC.cntPOC NOT IN ( SELECT cntPOC
FROM tblParcelToPOC
WHERE cntParcel = " + cntParcel + #"
AND cntAsOf = 0 )
AND tblPOC.ysnActive = 1 ORDER BY INITCAP(strLastName)";
cmd.CommandText = SQL;
cmd.CommandType = CommandType.Text;
using (reader = cmd.ExecuteReader())
{
while (reader.Read())
{
POCs.Add(new TBLPOC { CNTPOC = (decimal)reader[0],
STRLASTNAME = reader[1].ToString(),
STRFIRSTNAME = reader[2].ToString() });
}
}
Context.Database.Connection.Close();
return POCs;
Replacement code
var sql = string.Empty;
if (IsAssociate == 0)
sql = string.Format(#"SELECT tblPOC.cntPOC,INITCAP(strLastName),INITCAP(strFirstName)
FROM tblPOC,tblParcelToPOC
WHERE tblParcelToPOC.cntPOC = tblPOC.cntPOC
AND tblParcelToPOC.cntAsOf = 0
AND tblParcelToPOC.cntParcel = {0}
ORDER BY INITCAP(strLastName)",
cntParcel);
else
sql = string.Format(#"SELECT cntPOC,INITCAP(strLastName), INITCAP(strFirstName)
FROM tblPOC
WHERE tblPOC.cntPOC NOT IN (SELECT cntPOC
FROM tblParcelToPOC
WHERE cntParcel = {0}
AND cntAsOf = 0)
AND tblPOC.ysnActive = 1
ORDER BY INITCAP(strLastName)",
cntParcel);
return Context.Database.SqlQuery<TBLPOC>(sql, "0").ToList<TBLPOC>();
The issue I'm having right now is when the replacement code is executed, I get the following error:
The data reader is incompatible with the specified 'TBLPOC'. A member of the type 'CNTPOCORGANIZATION', does not have a corresponding column in the data reader with the same name.
The field cntPOCOrganization does exist within tblPOC, as well as within the TBLPOC Entity. cntPOCOrganization is a nullable decimal (don't ask why decimal, I myself don't get why the previous contractors used decimals versus ints for identifiers...). However, in the past code and the newer code, there is no need to fill that field. I'm confused on why it is errors out on that particular field.
If anyone has any insight, I would truly appreciate it. Thanks.
EDIT: So after thinking on it a bit more and doing some research, I think I know what the issue is. In the Entity Model for TBLPOC, the cntPOCOrganization field is null, however, there is an object tied to this Entity Model called TBLPOCORGANIZATION. I'm pondering if it's trying to fill it. It too has cntPOCOrganization within itself and I'm guessing that maybe it is trying to fill itself and is what is causing the issue.
That maybe possibly why the previous contractor wrote the Oracle Command versus run it through the Entity Framework. I'm going to revert back for time being (on a deadline and really don't want to play too long with it). Thanks!
This error is issued when your EF entity model does not match the query result. If you post your entity model you are trying to fetch this in, the SQL can be fixed. In general you need to use:
sql = string.Format(#"SELECT tblPOC.cntPOC AS <your_EF_model_property_name_here>,INITCAP(strLastName) AS <your_EF_model_property_name_here>,INITCAP(strFirstName) AS <your_EF_model_property_name_here>
FROM tblPOC,tblParcelToPOC
WHERE tblParcelToPOC.cntPOC = tblPOC.cntPOC
AND tblParcelToPOC.cntAsOf = 0
AND tblParcelToPOC.cntParcel = {0}
ORDER BY INITCAP(strLastName)",
cntParcel);

Reading results of SP with OdbcDataReader gives Error 22018 - Error in assignment

Ok I don't get this. I haven't used ODBC classes before but figuered it's nothing special for basic use. And it does work except in this case.
I need to execute stored procedure without parameters via ODBC connection and get the results, parse the rows into objects and insert them in my local DB. And it worked with test data but now fails with live data, while customer is able to execute the same PS via some other tool... The real trouble is that I have to run it on live server, so I can't debug, instead I created small project which writes output into TextBox. Anyway, here's the code:
var ODBCConnection = new OdbcConnection();
ODBCConnection.ConnectionString = "something...";
//using command "exec schema.spName" or "exec schema.spName()" or "{ call schema.spName()}" runs the procedure
//putting only name "schema.spName" gives ERROR [42000]
var cmd = new OdbcCommand("exec schema.spName())", ODBCConnection);
cmd.CommandType = CommandType.StoredProcedure;
DbReader = cmd.ExecuteReader();
int fCount = DbReader.FieldCount;
infoBox1.Text += System.Environment.NewLine + "Results:";
for (int i = 0; i < fCount; i++)
{
String fName = DbReader.GetName(i);
infoBox1.Text += fName + "|";
}
This list all the column names in result and there are 20 columns.
while (DbReader.Read())
{
var row = new RowClass();
for (int i = 0; i < fCount; i++)
{
object val = DbReader.GetValue(i);
//check which column this is and parse it to set properties of RowClass
//Expected values are string, int and decimal
}
}
This works for the first 10 rows but breaks when it tries to read for following columns with error:
ERROR [22018] [Cache ODBC][State : 22005][Native Code 22005]
[path to .exe]
Error in assignment
No StackTrace no InnerException.
I tried skipping 11th column because it started there, but breaks for every column after the first 10.
I am clueless... if it read there are 20 fields then wtf... null values are not problem because it returns DBNull, it works on other places (not executing SP but doing select queries).
Client executed sp connectin from same net environment and send me picshot, and csv of data. Nothing strane in data itself.
Anyone had this before? Should I use something else for instead of OdbcDataReader?
Thank you.
OK, I managed to figure it out thanks to customer admin who was executing the same procedure by some browser SQL tool. There I saw that 11th column was of type Date. ODBC returned type INT for that column. So I had to call another admin who set up ODBC and he changed column type to varchar so now it finally works.
I guess I can now assume how DataReader works if one wrong column type made all subsequent columns impossible to read as well.
I don't feel like accepting my own answer, so if someone would be kind enough to give me few links about how ODBC works and how DataReader works, not just how to use it, and maybe can quote some text that explains this behavior for this kind of mistake...

Insert the whole value of DataTable bulk into postgreSQL table

In SQL we do something like this for bulk insert to datatable
SqlBulkCopy copy = new SqlBulkCopy(sqlCon);
copy.DestinationTableName = strDestinationTable;
copy.WriteToServer(dtFrom);
Blockquote
but in PostgreSQL how to do this operation
Simple Insert Using Parameters
Your project will need to reference the following assembly: Npgsql. If this reference is not visible within Visual Studio, then:
browse to the connector's installation folder
Execute: GACInstall.exe
Restart Visual Studio.
Sample Table
CREATE TABLE "OrderHistory"
(
"OrderId" bigint NOT NULL,
"TotalAmount" bigint,
CONSTRAINT "OrderIdPk" PRIMARY KEY ("OrderId")
)
WITH (
OIDS=FALSE
);
ALTER TABLE "OrderHistory"
OWNER TO postgres;
GRANT ALL ON TABLE "OrderHistory" TO postgres;
GRANT ALL ON TABLE "OrderHistory" TO public;
ALTER TABLE "OrderHistory" ALTER COLUMN "OrderId" SET (n_distinct=1);
GRANT SELECT("OrderId"), UPDATE("OrderId"), INSERT("OrderId"), REFERENCES("OrderId") ON "OrderHistory" TO public;
GRANT SELECT("TotalAmount"), UPDATE("TotalAmount"), INSERT("TotalAmount"), REFERENCES("TotalAmount") ON "OrderHistory" TO public;
Sample Code
Be sure to use the following directives:
using Npgsql;
using NpgsqlTypes;
Enter the following source code into your method:
// Make sure that the user has the INSERT privilege for the OrderHistory table.
NpgsqlConnection connection = new NpgsqlConnection("PORT=5432;TIMEOUT=15;POOLING=True;MINPOOLSIZE=1;MAXPOOLSIZE=20;COMMANDTIMEOUT=20;COMPATIBLE=2.2.4.3;DATABASE=test;HOST=127.0.0.1;PASSWORD=test;USER ID=test");
connection.Open();
DataSet dataSet = new DataSet();
NpgsqlDataAdapter dataAdapter = new NpgsqlDataAdapter("select * from OrderHistory where OrderId=-1", connection);
dataAdapter.InsertCommand = new NpgsqlCommand("insert into OrderHistory(OrderId, TotalAmount) " +
" values (:a, :b)", connection);
dataAdapter.InsertCommand.Parameters.Add(new NpgsqlParameter("a", NpgsqlDbType.Bigint));
dataAdapter.InsertCommand.Parameters.Add(new NpgsqlParameter("b", NpgsqlDbType.Bigint));
dataAdapter.InsertCommand.Parameters[0].Direction = ParameterDirection.Input;
dataAdapter.InsertCommand.Parameters[1].Direction = ParameterDirection.Input;
dataAdapter.InsertCommand.Parameters[0].SourceColumn = "OrderId";
dataAdapter.InsertCommand.Parameters[1].SourceColumn = "TotalAmount";
dataAdapter.Fill(dataSet);
DataTable newOrders = dataSet.Tables[0];
DataRow newOrder = newOrders.NewRow();
newOrder["OrderId"] = 20;
newOrder["TotalAmount"] = 20.0;
newOrders.Rows.Add(newOrder);
DataSet ds2 = dataSet.GetChanges();
dataAdapter.Update(ds2);
dataSet.Merge(ds2);
dataSet.AcceptChanges();
connection.Close();
Thoughts On Performance
The original posting made no mention of performance requirements. It was requested that the solution must:
insert using a DataTable
insert data without using a loop
If you are inserting significant amounts of data, then I would suggest that you take a look at your performance options. The Postgres documentation suggests that you:
Disable Autocommit
Use the COPY command
Remove indexes
Remove Foreign Key Constraints
etc.
For more information about optimizing Postgres inserts, please take a look at:
PostgresSql.org: Inserting Data
PostgresSql.org: Insert + Performance Tips
StackOverflow: How to speed up insertion performance in PostgreSQL
Also, there are a lot of other factors that can impact a system's performance. For a high level introduction, take a look at:
ADO.NET SQL Server Performance bottleneck
This posting outlines general (i.e. non-SqlServer) strategies for optimizing performance.
Other Options
Does the .NET connector support the Postgres Copy command?
If not, you can download the source code for the Npgsql connector and add your own BulkCopy() method. Be sure to review the source code's licensing agreement first.
Check to see if Postgres supports Table Value Parameters.
This approach allows you to pass in a table into a Postgres function which can then insert the data directly into the destination.
Purchase a Postgres .NET connector from a vendor which includes the required feature.
Additional References
Postgres .NET Connector - free & open source
I've got the same problem a time ago. It seems there is no "ready to use" solution, till yet.
I've read this post and build a similar solution at that time, which is in productive use till today. Its based on text querys which reads files from STDIN. It uses the ADO.NET Postgre Data Provider Npgsql. You can create a large string (or temporary file, cause of memory usage) based on your DataTable and use that one as text query with the COPY command. In our case it was much more faster than inser teach row.
Maybe this isn't a complete solution, but may a good point to start and anything i know about it. :)
I have also found, that there are no 'ready to use' solution yet. Probably you can check my other answer in which I describe a little helper I have created for this problem, making use of another helper really easy: https://stackoverflow.com/a/46063313/6654362
I think that's currently the best solution.
I posted the solution from the link in case the post died.
Edit:
I have recently run into similar problem, but we were using Postgresql. I wanted to use effective bulkinsert, what turned out to be pretty difficult. I haven't found any proper free library to do so on this DB. I have only found this helper:
https://bytefish.de/blog/postgresql_bulk_insert/
which is also on Nuget. I have written a small mapper, which auto mapped properties the way Entity Framework:
public static PostgreSQLCopyHelper<T> CreateHelper<T>(string schemaName, string tableName)
{
var helper = new PostgreSQLCopyHelper<T>("dbo", "\"" + tableName + "\"");
var properties = typeof(T).GetProperties();
foreach(var prop in properties)
{
var type = prop.PropertyType;
if (Attribute.IsDefined(prop, typeof(KeyAttribute)) || Attribute.IsDefined(prop, typeof(ForeignKeyAttribute)))
continue;
switch (type)
{
case Type intType when intType == typeof(int) || intType == typeof(int?):
{
helper = helper.MapInteger("\"" + prop.Name + "\"", x => (int?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type stringType when stringType == typeof(string):
{
helper = helper.MapText("\"" + prop.Name + "\"", x => (string)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type dateType when dateType == typeof(DateTime) || dateType == typeof(DateTime?):
{
helper = helper.MapTimeStamp("\"" + prop.Name + "\"", x => (DateTime?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type decimalType when decimalType == typeof(decimal) || decimalType == typeof(decimal?):
{
helper = helper.MapMoney("\"" + prop.Name + "\"", x => (decimal?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type doubleType when doubleType == typeof(double) || doubleType == typeof(double?):
{
helper = helper.MapDouble("\"" + prop.Name + "\"", x => (double?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type floatType when floatType == typeof(float) || floatType == typeof(float?):
{
helper = helper.MapReal("\"" + prop.Name + "\"", x => (float?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type guidType when guidType == typeof(Guid):
{
helper = helper.MapUUID("\"" + prop.Name + "\"", x => (Guid)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
}
}
return helper;
}
I use it the following way (I had entity named Undertaking):
var undertakingHelper = BulkMapper.CreateHelper<Model.Undertaking>("dbo", nameof(Model.Undertaking));
undertakingHelper.SaveAll(transaction.UnderlyingTransaction.Connection as Npgsql.NpgsqlConnection, undertakingsToAdd));
I showed an example with transaction, but it can also be done with normal connection retrieved from context. undertakingsToAdd is enumerable of normal entity records, which I want to bulkInsert into DB.
This solution, to which I've got after few hours of research and trying, is as you could expect much faster and finally easy to use and free! I really advice you to use this solution, not only for the reasons mentioned above, but also because it's the only one with which I had no problems with Postgresql itself, many other solutions work flawlessly for example with SqlServer.

Concurrency Error updating a row a second time C#

HI I am getting the "Concurrency violation the updatecommand affected 0 of the expected 1 records." error while trying to update a row, weird thing is that I CAN update the row a single time and next time I repeat the process on the same row I get the error, I have already tryed the endinit and endedit thingys, any help would be appreciated!
I am using c# and MySQL innodb
string cs = "server=" + fidaConfig.dtBDConfig.Rows[0][2] + ";user id=root;Password=" + fidaConfig.dtBDConfig.Rows[0][4] + ";persist security info=True;database=facturas";
MySql.Data.MySqlClient.MySqlConnection conn = new MySql.Data.MySqlClient.MySqlConnection() { ConnectionString = cs };
switch (tableInvoice)
{
case "factura_idj":
dsLuiscencioTableAdapters.factura_idjTableAdapter idjAdapter = new Control_Administrativo.dsLuiscencioTableAdapters.factura_idjTableAdapter() { Connection = conn };
dsLuiscencio.factura_idjDataTable idj = idjAdapter.GetData();
var facturaidj = (from f in idj where f.no_factura_idj == InvoiceNumber select f).Single();
if (DateTime.Today.Date >= Convert.ToDateTime("01-01-2010") && facturaidj.fecha.Date <= Convert.ToDateTime("01-01-2010"))
{
var quieresactualizar = MessageBox.Show("Desea Actualizar el total de acuerdo a los nuevos impuestos?", "Reforma Fiscal", MessageBoxButtons.YesNo);
if (quieresactualizar == DialogResult.Yes)
{
switch (facturaidj.opt_iva)
{
case 1:
facturaidj.iva = 0;
facturaidj.total = facturaidj.subtotal;
break;
case 2:
facturaidj.iva = facturaidj.subtotal * 0.11;
facturaidj.total = facturaidj.subtotal * 1.11;
break;
case 3:
facturaidj.iva = facturaidj.subtotal * 0.16;
facturaidj.total = facturaidj.subtotal * 1.16;
break;
default:
break;
}
Number2Letter.Number2Letter n2l = new Number2Letter.Number2Letter();
string totalwithnocents = n2l.Numero2Letra(facturaidj.total.ToString(), 0, 0, "peso", "",
Number2Letter.Number2Letter.eSexo.Masculino,
Number2Letter.Number2Letter.eSexo.Masculino).ToUpper();
string strtotalconivaretenido = Math.Round(facturaidj.total, 2, MidpointRounding.ToEven).ToString("###########.00");
string cents = strtotalconivaretenido.Substring(strtotalconivaretenido.IndexOf(".") + 1);
facturaidj.total_letra = string.Format(#"{0} {1}/100 {2}", totalwithnocents, cents, facturaidj.tipo_moneda).ToUpper();
idj.EndInit();
idjAdapter.Update(facturaidj);//this runs only the first time on a row, then throws the error
}
}
break;
continues......
I don't know if this will have anything to do but:
I've finaly found my problem, this was
not related to concurency at all, i've
found the problem by testing the same
code on a SQL Server database, it was
giving me another error message, so
then i figure out that maybe MS Access
was wrong with his error, and the
problem was something else!
In addition you have the FLOAT issue mentioned before:
MySqlCommandBuilder composes the
UPDATE command using WHERE col=?1 AND
col=?2 ... In FLOAT columns you'll
never find an exact value in this way.
Which can perfectly be extended to double values... the problem seems to be a combination of a incorrect error message when the update tries to find the value to update
Could you try running the update command without actually updating anything? That is, instead of making an actual update, remove all the code except for the Update command so that the factura object is exactly the same and see if that works.
I am not sure if you are using float data types in your database, but this article might be what is happening to you: MySql - Float Issue
What is the SQL behind idjAdapter.Update() and how was it generated? Did you use the drag/drop designer in Visual Studio? If you did, then you will want to check the auto-generated update script? In my experience with the designer code in the MS SQL world, it will often include a very complicated WHERE statement where it only updates if every single old field of the row still exists.
If your table happens to contain an auto-generated time stamp field, or something similar, then you can run into issues with two users where this field may get updated behind your back, and so the WHERE in the update will fail, causing this concurrency exception to be thrown by the adapter.
You will then need to decide how to handle the issue. If you simply want to have last in wins logic, then you need to manually change the Update SQL in the designer (from the properties window of the designer for that table adapter) to only include your primary key for the table in the WHERE clause of the Update statement.

Categories