In a MFC application I like to map SQL date values (CDBVariant) to MFC CTime. Because the database entries can be NULL (value does not exist), I wonder if CTime is nullable. The remark in the MFC documentation to CTime::Format makes me thinking, it should be possible:
If the status of this CTime object is null, the return value is an empty string.
But how to set this status, is it even possible?
If it isn't possible, I guess boost::optional<CTime> would be a good alternative?
CTime is just a wrapper for a __time64_t. When you call format it does this:
inline CString CTime::Format(_In_z_ LPCTSTR pFormat) const
{
if(pFormat == NULL)
{
return pFormat;
}
TCHAR szBuffer[maxTimeBufferSize];
struct tm ptmTemp;
if (_localtime64_s(&ptmTemp, &m_time) != 0)
{
AtlThrow(E_INVALIDARG);
}
if (!_tcsftime(szBuffer, maxTimeBufferSize, pFormat, &ptmTemp))
{
szBuffer[0] = '\0';
}
return szBuffer;
}
So the system function you want to look at is _tcsftime. And this is where I think the documentation is not very accurate. If the _localtime64_s fails you'll get an exception so a 'null' time can't really be passed to _tcsftime. You'll only get a NULL if _tcsftime fails but that won't be because of a 'null' time.
So, in short, use something like you suggest of boost::optional to represent null.
Related
I have the following model method:
public IQueryable<CustomerVLAN> CustomerVLANS(int customerid)
{
string customername = entities.AccountDefinitions.SingleOrDefault(a=>a.ORG_ID == customerid).ORG_NAME;// .tolist since i will be querying different context
return tms.CustomerVLANS.Where(String.Compare(a=>a.CustomerName.ToString(), customername.ToString(), StringComparison.OrdinalIgnoreCase));
}
but I am unable to use the String.Compare inside my where clause ,,,
Provided CustomerName and customername are strings, you can try
return tms.CustomerVLANS.Where(a=>a.CustomerName.ToUpper() == customername.ToUpper());
The Where extension filters an IEnumerable using a supplied predicate function: Func<TSource, bool>, in your case Func<CustomerVLAN, bool>.
Your line "String.Compare(a=>a.CustomerName.ToString(), customername.ToString(), StringComparison.OrdinalIgnoreCase)" returns an integer, rather than a Func<CustomerVLAN, bool> delegate (I'm also not sure if there's an overload of string Compare which expects the values you've provided).
If you wanted to use that particular function, you'd have to do something like this (using a Lambda expression):
CustomerVLANS.Where(x => (String.Compare(x.CustomerName, customername, StringComparison.OrdinalIgnoreCase) == 0));
Unless there's a particular reason for it, you may well be better of using String.Equals, which returns a boolean:
CustomerVLANS.Where(x => (String.Equals(x.CustomerName, customername)));
You may need your ToString(), depending on what type CustomerName is.
I have a SQL statement similar to:
SELECT DATEDIFF(Day, startDate, endDate) FROM Data WHERE ProjectId=#id
In the case where Data doesn't have any records for ProjectId, SQL Server returns null.
In Dapper, I execute this via:
value = conn.Query<int>("...").SingleOrDefault()
In this case, I expect the semantics of SingleOrDefault to mean "if this is null, return zero." In fact, my code is even more zero-friendly:
int toReturn = 0;
using (var conn = ...) {
toReturn = conn.Query<int>("SELECT DATEDIFF(...))");
}
return toReturn;
When I debug and step into this code, I find that the line yield return (T)func(reader) is throwing a null pointer exception.
Am I doing something wrong here, or is this by design?
(FYI, the work-around is to wrap my select in an ISNULL(..., 0))
In the case where Data doesn't have any records for ProjectId, SQL Server returns null.
In the case where Data doesn't have any matching records, SQL server does not really return null - it returns no rows. This scenario works fine:
var result = connection.Query<int>( // case with rows
"select DATEDIFF(day, GETUTCDATE(), #date)", new { date = DateTime.UtcNow.AddDays(20) })
.SingleOrDefault();
result.IsEqualTo(20);
result = connection.Query<int>( // case without rows
"select DATEDIFF(day, GETUTCDATE(), #date) where 1 = 0", new { date = DateTime.UtcNow.AddDays(20) })
.SingleOrDefault();
result.IsEqualTo(0); // zero rows; default of int over zero rows is zero
both of which work fine. The fact that you say ISNULL "fixes" it means that you are talking about a different scenario - the "I returned rows" scenario. Since that is the case, what your code is saying is "take this 1-or-more integers which contains a null, and map it as a non-nullable int" - that isn't possible, and the mapper is correct to throw an exception. Instead, what you want is:
int? result = connection.Query<int?>(...).SingleOrDefault();
Now, if there are rows, it is mapping the value to int?, and then applying the single-or-default. It you want that as an int, then maybe:
int result = connection.Query<int?>(...).SingleOrDefault() ?? 0;
If you need to be able to tell the difference between "zero rows" and "null result", then I would suggest:
class NameMe {
public int? Value {get;set;}
}
var row = connection.Query<NameMe>("select ... as [Value] ...", ...)
.SingleOrDefault();
if(row == null) {
// no rows
} else if(row.Value == null) {
// one row, null value
} else {
// one row, non-null value
}
or something similar
Whats the use of using custom comparers in Linq queries? Are they beneficial or are they just an overload on the server.
So i am talking about queries like
IEnumerable<Class> GetMatch(Class comparerObject)
{
return Session.Linq<Class>().Where(x=>new StringComparer<Class>().Equals(x,comparerObject))
}
and this is how my stringcomparer class looks like
public class StringComparer<T> : IEqualityComparer<T>
where T : class, IStringIdentifiable
{
public bool Equals(T x, T y)
{
if (x == null && y == null)
return true;
if (x == null || y == null)
return false;
return x.Id.Equals(y.Id, StringComparison.OrdinalIgnoreCase);
}
So I was wondering how is this query run against the db? I think linq handles this internally where in it sends a request to the db only after all the cases in the comparere are run.
Edit:
Well if you are finding it hard to believe that the above will not work then take a simple example like
return Session.Linq<Class>().Where(x=>x.Id.Equals(comparerObject,StringComparison.InvariantCultureIgnoreCase))
Then what do you think is the expected behavior?
Thanks.
For LINQ to SQL, I'd expect that to fail at execution time - the query translator won't know what to do with your StringComparer<T> class.
In the case you've given, you should just use:
string idToMatch = comparerObject.Id;
return Session.Linq<Class>().Where(x => x.Id == idToMatch);
More complicated cases may or may not be feasible depending on exactly what you want to achieve.
I have an issue using the Dynamic Expression API. I cannot seem to compare a DataTable field against DBNull.Value. The API is supposed to be able to "support static field or static property access. Any public field or property can be accessed.". However given the following query:
var whatever = table1.AsEnumerable()
.Join(table2.AsEnumerable(),
(x) => x.Field<int>("Table1_ID"),
(y) => y.Field<int>("Table2_ID"),
(x, y) => new { x, y})
.AsQueryable()
.Where("x[\"NullableIntColumnName\"] == DBNull.Value");
I end up getting the error: "No property or field 'DBNull' exists in type '<>f__AnonymousType0`2'"
Anyone have ideas on how to get around this? I can't use Submission.Field("NullableIntColumnName") in the string passed to the Where method either, btw, or else I would be able to compare against null instead of DBNull.Value.
Well, I finally got it. cptScarlet almost had it.
var values = new object[] { DBNull.Value };
...
.Where("x[\"NullableIntColumnName\"] == #0", values);
or
.Where("x[\"NullableIntColumnName\"] == #0", DBNull.Value);
What happens when you replace your current .Where with something like
.Where(string.format("x[\"NullableIntColumnName\"] == {0}",DBNull.Value));
If you change x.Field<int>("Table1_ID") to x.Field<int?>("Table1_ID") then you'll get nullable integers instead of regular integers, and any DBNull values will be converted to simple C# null values. Based simply on your code snippet, I'm not even sure you'd need dynamic expressions - a simple .Where(foo => foo.x == null) ought to work.
In general, you can also try:
.Where("NullableColumnName.HasValue");
Sorry to non-answer with a USL but...
Have you looked in the source? There's not a lot of it. My guess is that DBNull is not in the list of registered root objects.
I dont have the source to hand right now, but it is also likely to tell you what any other constants one might compare against might be.
.Where(a => a.IntColName == null);
Edit:
Sorry, I did't see this dynamic requirement... Dynamic would be: (at least in Framework 4)
var intColName = "...";
.Where(string.Format("it.{0} is null", intColName));
Is there a way to get the code below to return null if no objects are found?
var news = (from c in childs
where c.Name.ToLower().Contains("folder")
select c).First();
You want to use FirstOrDefault() instead of First(). It will do exactly what you want.
You should call FirstOrDefault<T>, which will return default(T) if there are no elements.
default(T) will be null for reference and nullable types, 0 for numeric types (byte, int, double, etc), and new T() for structures (which cannot be null)