I'm having a weird issue concerning Microsoft SQL Compact Edition. In a Windows.Forms application, I try to modify a database which was created by the same (.Net 2.0) application. The database gets sent to a Windows Mobile Phone later, but this is not important. What's important is that on the normal regional settings of my computer, which is English (USA), inserting DateTime values in the database happens without any problems. However, when I switch the locale to Dutch (Netherlands), I get the following error:
"There was an error in a part of the date format. [ Expression (if known) = ]"
I tracked it down to the way DateTime looks in NL. However, I do not use DateTime.ToString(). I add it to the SQL insert/update statements purely as "column = " + DateTime. This works perfectly in "en-US" but when I switch to Dutch, it blows up.
The way I fixed this is by creating an extension method for the DateTime datatype like so:
/// <summary>
/// Transforms a DateTime from various cultures into what SQL compact expects to get.
/// </summary>
/// <param name="original">DateTime to process.</param>
/// <returns>A SQL-friendly string.</returns>
public static string _ToSQLDateTimeString (this DateTime? original)
{ //No provided Date? Bye.
if (original == null) return null;
IFormatProvider usDate = new CultureInfo("en-US");
return ((DateTime)original).ToString(usDate);
}
But I would like somebody to maybe confirm / improve my solution. Maybe I missed something?
But "column = " + DateTime implicitly calls ToString() on the DateTime.
You should use System.Data.SqlClient.SqlCommand and add the dates (and all other parameters) with command.Parameters.Add(...).
This will fix all localization issues with dates, floats, etc. And protect your application from SQL injection attacks.
If you want to push the DATETIME into the database a string, you're best of using the 2010-08-25T07:26:05 format - however, better would be to create a command object with parameters of the right types and then set the DATETIME parameter to the DateTime object rather than stringifying it.
SQL Server won't convert abritrary date string formats - it'll use the format dictated by whichever locale it's running under (default is US).
Related
The following sql (Sql Server 2016) generates an error:
INSERT INTO Requests (EntryDate,Status, AccountID)
VALUES (#EntryDate,#Status,#accountID)";
try
{
DatabaseConnection.Execute(sql,
new
{
DateTime.Now,
Status = (int)Status.New, '''an enum
accountID,
}, this.Transaction);
This generates the error:
Must declare scalar variable #EntryDate.
If I replace #EntryDate with getdate(), this runs OK. Even though it seems that getdate() is not used. Why this one value?
#EntryDate is a parameter of your command. You must supply it as such, even if the value is unused, otherwise SQL Server will look for a variable named #EntryDate (which likewise doesn't exist).
If you write new { DateTime.Now, ... } you are passing an anonymous object with a property named Now, which can't be mapped to the actual parameter. Change DateTime.Now to EntryDate = DateTime.Now so the name matches up. The question doesn't specify which object-relational mapper you are using (Dapper?) but they will all need to pass named parameters somehow.
I have an vb.net app that handles directory service attributes. I have to display the attribute values. To get the values I use LDAP.
Microsoft's Active Directory has the syntax (or type) LARGE_INTEGER / INTEGER8. I saw various LDAP-Browsers that display this type of attribute as DateTime. But Microsoft's documentation says that this syntax (or type) is a 64-bit signed integer value.
My question: Does the schema definition provide an information where I can detect that an attribute with the LARGE_INTEGER syntax should be handled as DateTime or not?
Here is an example:
lastLogoff -> DateTime
msExchVersion -> No DateTime
Both attributes have the same syntax.
Thank you for helping!
Yes. The LARGE_INTEGER thing is an abstraction at the ADSI layer. If you look at the docs for the lastLogoff attribute, for example (http://msdn.microsoft.com/en-us/library/ms676822(v=vs.85).aspx), you'll see the actual AD syntax is Interval. You can grab the syntax for a given attribute off the attribute definition in the schema.
Regarding to the following post it seems that there is no way to see whether a LARGE_INTEGER attribute should be handled as DateTime or not :\
Same datatype Storage but different representation in AD (UsnChanged and LastLogon)
When designing data tables in the .xsd designer in Visual Studio, there is a property that specifies what to do when the table encounters a null value:
The problem is, if the DataType is System.DateTime, I'm unable to return empty or nothing. It always throws an exception.
As I work around, I can do the following:
If(row.IsDateLastRecallPrintedNull, DateTime.MinValue, row.DateLastRecallPrinted)
But if the value is DbNull.Value, I'd rather just have it return that.
Using IsDateLastRecallPrintedNull isn't a workaround, it's the way it's intended to be used. If you use a nullable date, you can set this to nothing rather than DateTime.MinValue in your code. Alternatively you can change the datatype in the dataset to System.Object, and then you can select '(Nothing)' in the dropdown. Note that you can overtype the NullValue entry in the properties with another value that's appropriate for the data type, although it won't work if you enter DateTime.Minvalue - it'll appear to accept it, but then fail - but you can put in another magic number such as 01/01/1900.
All this is 'by design'.*
Using databinding sidesteps this quagmire to a great extent; if you're reading programmatically from the dataset then IsxxxNull is the way to go.
*I suspect this is too often a Microsoftism for 'we didn't finish it by ship date'
Given a table Element with a DateTime field birthday (not null), in Entity framework 4 I am allowed to do:
Dim mylist = (From el in Element Select el).ToList()
.Select(function(el) new with {
.bday = el.birthday.toString("dd/MM/yy")
}
I am now required to change birthday to be nullable, therefore I change the table in SQL server and then update my ModelDB in Visual studio.
The result is that the line:
.bday = el.birthday.toString("dd/MM/yy")
raises an exception as "Invalid cast from integer to string "dd/mm/yy").
The only way to get it "fixed" is to change the line this way:
.bday = CDate(el.birthday).toString("dd/MM/yy")
Is this the correct approach?
Now that I have a nullable Datetime, how to handle the case when el.birthday is null?
Thanks!
If you do a small experiment, you would understand perfectly what is happening:
Dim normalDate As Date = Now
Dim nullableDate As Nullable(Of Date) = normalDate
Dim normalToText As String = normalDate.ToString("dd/MM/yy") 'Works perfectly
Dim nullableToText As String = nullableDate.ToString("dd/MM/yy") 'Error
The content in both variables, normalDate and nullableDate, is identical but they are not: the ToString("date in certain format") functionality expects a Date type as input; what you are sending is a modified version of the Date type (not too different, but not the same either). With CDate what you are doing is converting the modified version of Date into an actually valid Date type and thus the ToString() functionality works without any problem.
Are you doing the right thing? Yes, as far as CDate can deal with "nulls" (CDate(Nothing) does not output any error): you are adapting the given variable to what ToString() expects.
NOTE: I have checked the exact error output by the code above and it effectively delivers a "Conversion from string "dd/MM/yy" to type 'Integer' is not valid.". Thus the error you are getting is the standard error when intending to use ToString("date") with a Nullable Date; not too descriptive error, this is true.
When dealing with nullable properties, the db column is mapped to System.Nullable(Of T) (See Documentation). So in your case, the el.birthday should have been mapped to Nullable(Of DateTime). This class has two properties to deal with the situation you have, that are, .Value (Doc) and .HasValue (Doc).
The actual type specific value is stored in .Value so in your case, you need to do something like this:
.bday = el.birthday.value.toString("dd/MM/yy")
Or you can use .HasValue which returns boolean to indicate if there is a value:
If el.birthday.HasValue Then
.bday = el.birthday.toString("dd/MM/yy")
End If
This is probably fairly straightforward but i can't seem to find a reasonable explanation in any documentation.
I'm trying to use an NHibernate.ISQLQuery and using SetResultTransformer() to return a custom set of results from a custom SQL query. Like so:
public virtual IList<T> GetSQLObject<T>(string sql, IDbParameter[] parameters = null)
{
ISQLQuery qry = _sess.CreateSQLQuery(sql);
qry.SetResultTransformer(Transformers.AliasToBean(typeof(T)));
if (parameters != null) {
foreach (IDbParameter parameter in parameters) {
qry.SetParameter(parameter.Name, parameter.Value);
}
}
return qry.List<T>();
}
From looking at the examples, it seems that in the sql query I have to use parameters in the format :param1 instead of #param1 as I would in a standard SQL query. If i use the latter syntax in the query, it throws an error at qry.SetParameter().
Is there a reason why ISQLQuery/NHibernate requires them in this format and won't work with the normal syntax?
SQL Server uses #param, but not every other database does. For example, MySQL uses ?param
NHibernate allows you to swap out 1 database implementation for another with little to no reworking of your DAL. It sets the parameters based on the database you configured when you setup the NH Configuration.
Edit: Also I think :param came about from Hibernate being targeted at Oracle when it was initially developed, since Oracle uses :param
Phil has answered the "why"; so perhaps I can recommend a "how"; why not just add a new extension method to the IDbParameter type (something like .GetNHibernateName() ) that will return the parameter name with the "#" replaced with a ":"; that should be trivial to implement.