I've a timestamp column in my database which is used as rowversion. At the time of pulling data out of the database we get rowversion also which i converted into byte[]. Upto this stage everything works as expected.
At the time of updating data, i'd like to check (in a stored procedure), if the rowversion is the same or not, that is compare one that is being passed from code with one that is stored in database. If that differs i abort the update otherwise it updates the data.
Now my problem is, how to pass byte[] to a stored procedure. The parameter type in the stored procedure is timestamp.
Note : I make all the db operations in c# using enterprise library. I can't change the stored procedure or datatypes. Its restricted.
See code below :
DateTime now = DateTime.Now;
long bNow = now.ToBinary();
byte[] arrayNow = BitConverter.GetBytes(bNow);
long getLong = BitConverter.ToInt64(arrayNow, 0);
DateTime getNow = DateTime.FromBinary(getLong);
Console.WriteLine(getNow.ToLongTimeString());
Console.ReadLine();
Below code works as expected
public static TestMethod(....,byte[] rowVersion)
{
.........
dbConnection_.AddInParameter(dbcommand, "#row_version", DbType.Binary,rowVersion);
...........
}
Above code is using enterprise library. I think this will help someone.
Thank you all of you who tried to help here. Cheers..!
Related
I have a table with Column data type "timestamp" in sql server.
Currently I am trying to get the data from this table to sqlite database. as it needs only string value. So far i have not been able to find correct way to convert to string.
So for example my SQL Value is 0x0000000000012DE0
When I get the record using entity framework, I get byte array.
Tried to convert using following code to string.
value = BitConverter.ToInt64(Version, 0);
However for same record, i get 0xE02D010000000000
This is one difference.
The second, Since I am working on azure mobile app, and this data also goes to android via WebAPI controller.The result I get from fiddler is something in this format
AAAAAAABM8s=
I want to also convert the byte arrray value in above format .
Any suggestions?
I had a similar issue with my ASP.NET Core, EF Core 2.0, Angular 2 app. This was a database first development and changing the database definition was not within my remit.
In my case, EF Core automatically performed the concurrency check for me where the Timestamp column was present in the table. This was not an issue for updates because I could pass the DTO in the body but with deletes I could not.
To pass the timestamp I used a query string. The value being the Base64 string representation of the timestamp e.g. AAAAAAACIvw=
In my repository layer I convert the string back to a byte array e.g.
byte[] ts = Convert.FromBase64String(timestampAsBase64String);
Then delete using the create and attach pattern (thereby eliminating any chance of lost updates)
ModelClass modelobj = new ModelClass { Id = id, Timestamp = ts};
_dbcontext.Entry(modelObj).State = EntityState.Deleted;
Thanks to this thread and the CodeProject article Converting Hexadecimal String to/from Byte Array in C# to get this resolved.
I have been using the SQLiteAsyncConnection for all the database operations and it was recently I came to know that it doesn't allow association between tables. Now I am in the process of moving the code to use the SQLite.Net Extension which supports extensions. I have found a weird issue when I insert datetime data into the table. It completely changes the datetime on insertions.
App.db2.Insert(new FrequentlyAssignedShifts()
{
ShiftStart = Convert.ToDateTime(btnShiftStart.Content.ToString()),
ShiftEnd = Convert.ToDateTime(btnShiftEnd.Content.ToString()),
});
And this is how the connection is established.
string databasePath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "Scheduler.sqlite");
public static SQLiteConnection db2;
var platform = new SQLite.Net.Platform.WinRT.SQLitePlatformWinRT();
db2 = new SQLiteConnection(platform, databasePath);
I checked until the last point using breakpoints, whether the right data is getting inserted. It all seems fine, it is getting the right date from the button controls, but the moment it passes this part of the code the date value changes. The "ShiftStart & ShiftEnd" variables are datetime variables in the Table. Could someone please advise.
Thanks for reading the post.
Maybe too late but as far I can see, the time is saved as ticks on the database, so instead of using "Date" or "Timestamp" or anything else, use bigint, thus, the field will hold the time as ticks using UTC, once you retrieve the value from database use the function "ToLocalTime()" from DateTime and vioala!!!!
I have a .Net application using EF4 and both DB2 LUW and iSeries.
When we run a command on the DB2, we clone the original command into a new iDB2Command, copy the parameters, and run. It all works great, until we get to DATE columns. At that point the AS400 or the driver seems to fall down: it gets a parameter that says it is a DbTypes.DateTime, and contains a DateTime object, but the column is DATE.
The error returned (on LUW) is below. The AS400 (v6r1m0) returns a slightly different wording
ERROR [22008] [IBM] CLI0114E Datetime field overflow. SQLSTATE=22008
The code looks something like this (and is totally iSeries/DB2-LUW agnostic)
// all generic System.Data classes, no iDB2Connection datatype. The driver isn't even
// installed on dev/build machines at this point. We rely on .Net reading the connection
// string from App.config to create the proper DB Driver (db2-luw or iSeries)
DbConnection c = ... get connection from somewhere...
DbCommand cmd = c.CreateCommand();
var p = cmd.CreateParameter();
p.ParamterName = "V_XXX_XXX";
p.DbType = DbTypes.DateTime;
p.Value = DateTime.Now;
cmd.AddParamter(p);
...
So...
Is there anything we are doing wrong here? For LUW sending the parameter as a DbTypes.DateTime works just fine. EDIT: It worked just fine on LUW because we were sending a truncated date in local test code (eg, Now.Date). Normal DateTime.Now fails with truncation error just like on the AS400)
Also, we have complete metadata on the type, so in theory it is possible to tell, at conversion time, what System.DbTypes to convert to. We are hoping that is all that needs to be done (or hacky convert-to-string stuff), rather than some underlying issue.
** Solution **
Thanks to #mike-willis, we just check column before creating the command and do a manual truncation when required.
// get the db2 column type from our model metadata, because in .net it is all just DateTime
cmd.AddParamter("#MyDateColumn", FixParam( dateObject, metatdata.ColumnType);
// fix up different types of parameters. real version does a lot more validation
public object FixParam(object value, string db2columnType) {
if (db2columnType == "date") return ((DateTime)value).Date;
...
return value;
}
Thanks, all you DB2 folks.
Coming from the i, you can just assign from a DATE field to a DateTime field.
DateTime EmployeeSignedDateTime = i.Field<DateTime>("EMP_SIGNED_DATE").Add(i.Field<DateTime>("EMP_SIGNED_TIME").TimeOfDay)
In order to sent to the i, you can do that following:
p.Add("#EMPLOYEE_SIGNED_DATE", iDB2DbType.iDB2Date).Value = DateTime.Now.Date;
p.Add("#EMPLOYEE_SIGNED_TIME", iDB2DbType.iDB2Time).Value = DateTime.Now.ToString("HH.mm.ss");
Note that I am using the IBM.Data.DB2.iSeries.dll.
I had a datetime column in a SQL Server table. We needed to encrypt it. So, I cast it to a varbinary in SSMS. I simply edited the table, set the datetime type to varbinary and let SQL Server convert it. Following that, I wrote throwaway C# code to pull it out, encrypt it (using the encryption algorithms in our middle layer) and push it back into the database. Did the same for some nvarchars for names and other string types.
When I pull out the encrypted data (using NHibernate), I pull the varbinary into a byte[] and decrypt it. I then try to convert it back to the original value.
The nvarchar-as-varbinary columns convert fine; for example, I get may names back.
return Encoding.Unicode.GetString(source.FirstName);
However, I'm having a hard time converting the dates back into their original form. I'm using:
long ticks = BitConverter.ToInt64(source.DateOfBirth, 0);
return new DateTime?(new DateTime(1980, 1, 1).AddMilliseconds(ticks));
This does not seem to return the date properly. What's the correct way to cast it back to a DateTime?
Update: A sample value was requested. A datetime that was originally 1/1/1901, when decrypted, yields a byte[] where byte[2]=1 and byte[3]=109, and all others are 0. Another datetime '1941-04-26' yields byte[2]=58 and byte[3]=242 upon decryption.
The date is stored as the number of days since 1900-01-01.
Example:
byte[] data = {0,0,58,242};
if (BitConverter.IsLittleEndian) {
Array.Reverse(data);
}
int days = BitConverter.ToInt32(data, 0);
DateTime date = new DateTime(1900, 1, 1).AddDays(days);
Console.WriteLine(date);
Output:
1941-04-26 00:00:00
Int64 ticks = BitConverter.ToInt64(source.DateOfBirth, 0);
DateTime dt = DateTime.FromBinary(ticks);
After you decrypt the varbinary data, can you get the string value and run it through SSMS? Something like:
SELECT CONVERT(datetime, 0x0000A149016D7FD9)
What does your varbinary data look like in SQL Server? I suspect something is being messed up in translations.
Good luck.
I am decorating one of my DateTime property in my class with Representation = BsonType.Int64 attribute so that it gets stored in the database with Int64 representation of a date.
When I used to store that property as a normal C# Datetime and did not set the value to anything then it would store DateTime.Min in the database. That is perfect because I was doing reading from databse and doing Query.LT operation like following on it:
Query.LT("MyField", DateTime.Now));
And it used to return all the values fine.
Now that I started storing it as BsonType.Int64 and the equivalent of DateTime.Min in BsonType.Int64 is "0". my Query.LT("MyField", DateTime.Now)); fails on all the dates that are stored with DateTime.Min.
Any idea on how to solve this?
The problem is that, during the query, the MongoDB driver doesn't know that you chose an alternate representation.
Hence, you need to query for an Int64 explicitly:
Query.LT("MyField", DateTime.Now.Ticks));
This will work as expected (tested w/ MongoDB 2.1.1, C# driver 1.4.2.4500)