I have an app which worked fine with Sql Server. I have a DevExpress grid which shows just a record in carousel mode (not that this matters, I hope).
Now, I have changed the code to be database-agnostic and I'm testing MySql. When the user modified the record and accepted the changes, I was getting the following error:
Concurrency violation: the UpdateCommand affected 0 of the expected 1
records
After some research, I've come to the conclussion that the problem lies in DATETIME fields. I am using "Allow Zero Datetime=False; Convert Zero Datetime=True;" in my MySql connection string so I can convert default DATETIME values to .Net DateTime objects. The autogenerated UpdateCommand includes every field in the where clause, and I guess the comparison fails when the MySql DATETIMEs are set to the default value, as removing DATETIME fields the problem went away.
I have a Primary Key column, and the user isn't allowed to modify it, so what's the right way to issue a custom UpdateCommand so that there's only one field in the WHERE clause?
My current code for accepting changes:
Dim builder As DbCommandBuilder = m_Conn.CreateCommandBuilder(m_Adapter)
m_Adapter.Update(m_DataTable)
CreateCommandBuilder is an extension method on IDbConnection to create the correct an object with a correct implementatin of the DbCommandBuilder interface.
Your DBCommandBuilder should have a ConflictOption Property that needs to be set.
Presumably you want to set it to ConflictOption.OverwriteChanges.
I'm not sure if it works when you initialize the Adapter commands via the CommandBuilder Constructor but a
var builder = new MySqlCommandBuilder();
builder.ConflictOption = ConflictOption.OverwriteChanges;
builder.DataAdapter = m_Adapter;
should do.
Instead of using "Allow Zero Datetime=False; Convert Zero Datetime=True;" in your connection string (which FYI I'm not familiar with), I'd recommend using DateTime.Parse(value). You'll probably want to write a function so that you can easily handle nulls as well.
private DateTime getDateTimeField(string dbValue)
{
if (dbValue == null)
{
return new DateTime();
}
else {
return DateTime.Parse(dbValue);
}
}
Related
I use the layer2 cloud connector synchronisation tool to synchronize between a sql database and a sharepoint database on the right side. When synching from right to left (from SP to SQL) in a datetime field "dl date" there can be empty values. I established a dynamic column in the tool, which should return "01.01.1753" if in SP "dl date" was empty or just the regular date if it was not empty. That's due to our SQL database, which doesn't accept empty values but has to have this weird "01.01.1753" as empty value.
In the definition of the dynamic field I use the following C#-Code:
if(String.IsNullOrEmpty(NächstesFSKontrolldatum.ToString())) {
return DateTime.Parse("01.01.1753"); } else { return
NächstesFSKontrolldatum; }
But no matter how I compare the field "NächstesFSKontrolldatum" (aka "dl date") if it's null, it doesn't fire the part of the condition for beeing null.
When the tool finally writes just the date to sql there is an error which says can't put string '' into date field. I guess that always my second case of the condition fires and he tries to write just empty values into the database.
Because this code runs inside of the layer2 tool, I don't know how to debug or write to the console. Maybe you know or it's not possible?
Do you know, which comparison I have to make?
Andreas
I think is beter test if the 'NächstesFSKontrolldatum' can be parsed with a TryParse
DateTime testDate;
if(!DateTime.TryParse(NächstesFSKontrolldatum.ToString(), out testDate))
{
return DateTime.Parse("01.01.1753");
}
else
{
return testDate;
}
This way you're sure the value returned can be readed as a Date
I have search this problem on internet, but my issue is different.
I'm using Fluent NHibernate and try insert data with sql query:
var query = "INSERT INTO TABLE_NAME('ID','CONTENT') VALUES(:ID, :CONTENT)";
var executedQuery = Session.CreateSQLQuery(query);
executedQuery.SetParameter("ID", data.Id);
executedQuery.SetParameter("CONTENT", data.Content);
executedQuery.ExecuteUpdate();
Here data passing to method. In database(Oracle 11g) datatype of CONTENT is NCLOB. When try to insert data, I get this error:
ORA-01461: can bind a LONG value only for insert into a LONG column
What is problem in here?
This error is not very helpful and goggling it will most likely result in topics regarding oracle patches and the like. In reality this is a bug with the microsoft oracle client driver. The driver mistakenly infers the column type of the string being saved, and tries forcing the server to update a LONG value into a CLOB/NCLOB column type. The reason for the incorrect behavior is even more obscure and only happens when all the following conditions are met:
when we set the IDbDataParameter.Value = (string whose length is : 4000 > length > 2000 )
when we set the IDbDataParameter.DbType = DbType.String
when DB Column is of type NCLOB/CLOB
In this situation you must set database column type in set parameter method overload, so:
executedQuery.SetParameter("CONTENT", data.Content, NHibernateUtil.StringClob);
I'm fighting trough with Entity Framework 6 and MySQl Database
I got everything to work, however I'm confused with dates or not obligatory values.
In my database, in "Users" table I have column "RegistrationDate" which has default value of "CURRENT_TIMESTAMP"
what is mean that if value not provided at insertion time it will insert default value = date time of the server
I got my schema reverse engineered into C# and all perfectly works, however when I insert "User" without setting a date to "RegistrationDate" property, it insert into Database new date as "0001-01-01 00:00:00" and ignore "CURRENT_TIMESTAMP".
So im wondering how to set it to ignore "RegistrationDate" and do not insert anything into db if it wasn't specifically set to some date?
I have a guess that the SQL EF generates is setting the field value. Even if you don't set in code, EF doesn't know that the database has a default value, and doesn't know that he should ignore it.
This article, from 2011, says that there is a DatabaseGenerated attribute, which you could use like this:
[DatabaseGenerated(DatabaseGenerationOption.Computed)]
public DateTime RegistrationDate { get; set; }
So, EF now knows that it should retrieve the data when you query the database, but should rely on the database to set the value.
However, I don't know what it would do if you explicitly set the value. Maybe it will ignore it, which may be not what you really want.
I didn't test it, it's just a guess, but it's a nice solution in my opinion.
[Edit1] Some months ago, I saw this video, and the guy does something like this in his DbContext class (i believe you have it) at 49:12 (the video is in portuguese)(i have modified the code, but didn't test it):
//This method will be called for every change you do - performance may be a concern
public override int SaveChanges()
{
//Every entity that has a particular property
foreach (var entry in ChangeTracker.Entries().Where(entry => entry.Entity.GetType().GetProperty("YourDateField") != null))
{
if (entry.State == EntityState.Added)
{
var date = entry.Property("YourDateField");
//I guess that if it's 0001-01-01 00:00:00, you want it to be DateTime.Now, right?
//Of course you may want to verify if the value really is a DateTime - but for the sake of brevity, I wont.
if (date.CurrentValue == default(DateTime))
{
date.CurrentValue = DateTime.Now;
}
else //else what?
{
//Well, you don't really want to change this. It's the value you have set. But i'll leave it so you can see that the possibilities are infinite!
}
}
if (entry.State == EntryState.Modified)
{
//If it's modified, maybe you want to do the same thing.
//It's up to you, I would verify if the field has been set (with the default value cheking)
//and if it hasn't been set, I would add this:
date.IsModified = false;
//So EF would ignore it on the update SQL statement.
}
}
}
I think many of us have been caught out by default database values when dealing with EF - it doesn't take them into account (there are many questions on this - e.g. Entity Framework - default values doesn't set in sql server table )
I'd say if you haven't explicitly set a datetime and want it to be null, you'll need to do it in code.
I have the following c#/Query:
TrackDuration =TimeSpan.Parse( Request.Form["TrackDuration"].ToString());
string InsertQuery = string.Format("UPDATE tblTracks SET TrackLength={0}, TrackDuration='{1}', TrackName='{2}',TrackDescription='{3}',TrackMap='{4}',DifficultLevel={5},OverallHeight={6},IsCircular='{7}', ForBeginners='{8}',StartPoint='{9}',ParkingPlace='{10}',SeasonOfYear={11},TrackLocation={12}, Images='{13}' WHERE UserID={14}",
TrackLength, TrackDuration, TrackName, TrackDescription, TrackMap, DifficultID, OverallHeight, IsCircular, ForBeginners, StartPoint, ParkingPlace, SeasonID, AreaID, ImageList, UserID);
But I got this error message:
Syntax error in UPDATE statement
Syntax error (missing operator) in query expression
I realy tried to solve this, but I can't.
How can I fix this problem?
Update:
This is the value of the Query:
UPDATE tblTracks SET TrackLength=35, TrackDuration='02:30:00', TrackName='45',TrackDescription='<p>sometext.</p>
',TrackMap='f',DifficultLevel=3,OverallHeight=450,IsCircular='true', ForBeginners='false',StartPoint='<p>קיבוץיסעור </p>
',ParkingPlace='<p>כניסה לקיבוץ יסעור</p>
',SeasonOfYear=1,TrackLocation=3, Images='' WHERE UserID=1
The sql values types are:
TrackLength = number ; TrackDuration = date/time ; TrackName= string ;TrackDescription= string; TrackMap = string; DifficultLevel=number;OverallHeight=number;IsCircular=true/false;ForBeginners=true/false;
StartPoint=string; ParkingPlace=string; SeasonOfYear=number; TrackLocation=number;Images=string
'02:30:00' is not a correct value for datetime DB field, AFAIK. The default format is controlled by date format setting.
Additionally, '20130412' should work in any case, but for datetime field. You need to format the TrackDuration correctly or use CAST/CONVERT. As TimeSpan doesn't contain date part (it represents a duration and not a point in time), you can only make it up (e.g. prepend "20100101") but that is an awful hack.
The proper solution is to use the correct DB field type.
'02:30:00' might work if the field was of time type. Please read some more about time types in SQL Server.
Even better, why don't you use plain integer for the duration in seconds? The duration is not a date anyway.
The much bigger issue is that you are concatenating strings to set the command text, which opens you for SQL injection attack. If I name the racing track a';DROP TABLE tblTracks;-- your database is toast:
UPDATE tblTracks SET TrackLength=35,
TrackDuration='02:30:00',
TrackName='a';DROP TABLE tblTracks;-- ...
I am currently developing a C# MySQL Export Utility. Due to this I am not going to know the fields or the data types of each field in the table.
When I export the data from the table in the database it displays a MySQLConversionException stating that it is unable to Covert MySQL Date/Time to System.DateTime. It was doing this when I ran the code:
if (!reader.isDBNull(fieldCount)){}
However, when the exception was thrown on this line I fixed it by adding Allow Zero DateTime=true to the MySQL Connection string but not it is displaying the error when I run the code
string value = reader.getString(field);
How can I get around this issue bearing in mind I am not going to know what data type is or what the value is going to be.
Thanks for any help you can provide.
You can get the raw value as object:
object value = reader[field];
Then decide what to do based on its type:
if (value is string)
{
string sVal = value.ToString();
//handle as string...
}
else if (value is DateTime)
{
DateTime dtVal = (DateTime)value;
//handle as DateTime...
}
else
{
//some other type
}
Maybe not elegant, but should work.
If you read DATETIME values with MySQL Connector/Net and set 'Allow Zero Datetime', then you should use the reader.GetValue() method; in this case the reader will return a MySqlDateTime object with '0000-00-00 00:00:00' value.
Connector/Net Connection String Options Reference
Note, than .NET DateTime.MinValue = 00:00:00.0000000, January 1, 0001.
Also, try dotConnect for MySQL components.
I tackled a problem similar to this in an old open source project of mine. See it here in my Util.DefaultConvert() method.
The trick is to use Type.GetTypeCode() and switch on the result.
Then implement a strict conversion for each type. There is most likely other code in there you can check out to do what you need. I have a MySql provider in there as well.