Match dates in Linq, C#, SQL - c#

I am using the repository pattern to query SQL to get a record based on a date passed in via a web api. The query string is date=2014-09-16, for example. When my repository receives this date, the time is automatically set to 12:00:00 since one wasn't passed. I am only interested in matching the date in the database like this:
public IQueryable<Instance> GetInstances(DateTime date) {
return DBContext.Instances.Where(x => x.StartDateTime == date).OrderBy(x => x.StartDateTime).AsQueryable();
}
The problem is that no match is found since the records in the db are not a full match because of the time portion even though records exist for this date. What is the best way to get a match in the above example?

Here are all the default .NET methods EF supports. Only these are supported. If you want something else, you have to use these date functions: Entity Framework sqlFunctions, or put your code in a stored procedure or table function (which can be called by the context).

Related

Add date and time columns in where clause in Entity Framework 6

I have a SQL Server 2016 table of events where the event date and start time are stored in separate columns. I'm trying to write a query to identify which of a provided list of DateTimes already exist in the table so I need to add or combine the EventDate and StartTime columns before doing the comparison like this:
public List<DateTime> DoEventsExist(List<DateTime> dateBatch)
{
try
{
DBContext.Events.Where(ce => dateBatch.Contains(ce.EventDate.Add(ce.StartTime));
}
catch (Exception ex)
{
}
}
But this, of course, would give an exception with the message:
LINQ to Entities does not recognize the method 'System.DateTime Add(System.TimeSpan)' method, and this method cannot be translated into a store expression.
In this case the columns are of Date and Time types respectively (so the .NET types are DateTime and TimeSpan), but I'd also like to know how to accomplish this if they were both DateTime2 types where one contained a date at midnight and the other contained an irrelevant date with the correct time.
SqlFunctions.DateAdd would probably work but it would make my code tightly coupled with MS SQL Server, which I don't want.
Note
There is a similar question, however it does not ask about combining two DateTimes. Additionally it is not specific to EF 6, its answer predates EF 6, and the answer does not work so the whole question is useless to SO.
Given you have a list of datetime values, that style of query really isn't going to get you where you want to be.
As you suggest, change it to a TVP.
You can pass a TVP to a procedure as also suggested, but TVPs can also be passed to adhoc SQL queries as parameters.

Datetime format is 'mm-dd-yyyy' when getting while using SqlDataAdapter but if I run the same query in ms sql then its 'yyyy-mm-dd'

I know the question is a bit confusing. Please let me elaborate.
Suppose
I have a table student master which has a column DOB
I have inserted a record and in DOB I have inserted '1991-01-01'
running select statement from sql server is returning date in the same format as it is inserted '1991-01-01' but when I am running the same query from C# using SqlDataAdapter then its returning date as '01-01-1991'
Can anyone explain why it is happening and is there any way to fetch the date in same format as it is inserted.
Query
Is it possible to get the DateTime using SqlDataAdapter as it was inserted?
P.S: column data type is Datetime
let's separate the wheat from the chaff :)
if for your needs meaningful is data type (datetime in this case), then formatting does not matter at all. All layers which will exchange or process the data will use data type information for that.
But
if the meaningful part is formatting, i.e. string representation of the data, then you need to consider the appropriate settings of UI tools you use to display your data. SSMS, for example, uses regional settings for that. If you need to visualize data in the identical manner, so you need the identical strings, you should take care of formatting by your self or in another words, you need to convert your datetime data to string in the same way in all places where you need it.
In T-SQL, for example, you could use CAST and CONVERT functions for formatting your data in a format you need.
If you can't match up the "Cultures" between the SQL Server and the machine you're building the application on (and, in fact, you cannot rely on that really if you're application is going to be deployed to other machines!), then the cheap and quick way round it is to run your date returns through a parse function such as this:
private string FncFormatDate(string date)
{
DateTime formattedDate;
if (DateTime.TryParse(date, out formattedDate))
{
return formattedDate.ToString("yyyy-MM-dd");
}
else
{
return "Invalid date";
}
}
I hope this answers your question.

.Where clause on DateTime.Month

Here is the situation:
I'm working on a basic search for a somewhat big entity. Right now, the amount of results is manageable but I expect a very large amount of data after a year or two of use, so performance is important here.
The object I'm browsing has a DateTime value and I need to be able to output all objects with the same month, regardless of the year. There are multiple search fields that can be combined, but the other fields do not cause a problem here.
I tried this :
if(model.SelectedMonth != null)
{
contribs = contribs.Where(x => x.Date.Value.Month == model.SelectedMonth);
}
model.Contribs = contribs
.Skip(NBRESULTSPERPAGE*(model.CurrentPage - 1))
.Take(NBRESULTSPERPAGE)
.ToList();
So far all I get is "Invalid 'where' condition. An entity member is invoking an invalid property or method." I thought of just invoking ToList() but it doesn't seem to be very efficient, again the entity is quite big. I'm looking for a clean way to make this work.
You said:
The object I'm browsing has a DateTime value and I need to be able to output all objects with the same month, regardless of the year
...
I expect a very large amount of data after a year or two of use, so performance is important here.
Right there, you have a problem. I understand you are using LINQ to CRM, but this problem would actually come up regardless of what technology you're using.
The underlying problem is that date and time is stored in a single field. The year, month, day, hour, minute, seconds, and fractional seconds are all packed into a single integer that represents the number of units since some time. In the case of a DateTime in .NET, that's the number of ticks since 1/1/0001. If the value is stored in a SQL DateTime2 field, it's the same thing. Other data types have different start dates (epochs) and different precisions. But in all cases, there's just a single number internally.
If you're searching for a value that is in a month of a particular year, then you could get decent performance from a range query. For example, give all values >= 2014-01-01 and < 2014-02-01. Those two points can be mapped back to their numeric representation in the database. If the field has an index, then a range query can use that index.
But if the value you're looking for is just a month, then any query you provide will require the database to extract that month from each and every value in the table. This is also known as a "table scan", and no amount of indexing will help.
A query that can effectively use an index is known as a sargable query. However, the query you are attempting is non-sargable because it has to evaluate every value in the table.
I don't know how much control over the object and its storage you have in CRM, but I will tell you what I usually recommend for people querying a SQL Server directly:
Store the month in a separate column as a single integer. Sometimes this can be a computed column based on the original datetime, such that you never have to enter it directly.
Create an index that includes this column.
Use this column when querying by month, so that the query is sargable.
This is a guess and really should be a comment, but it's too much code to format well in a comment. If it's not helpful I'll delete the answer.
Try moving model.SelectedMonth to a variable rather than putting it in the Where clause
var selectedMonth = model.SelectedMonth;
if(selectedMonth != null)
{
contribs = contribs.Where(x => x.Date.Value.Month == selectedMonth);
}
you might do the same for CurrentPage as well:
int currentPage = model.CurrentPage;
model.Contribs = contribs
.Skip(NBRESULTSPERPAGE*(currentPage - 1))
.Take(NBRESULTSPERPAGE)
.ToList();
Many query providers work better with variables than properties of non-related objects.
What is the type of model.SelectedMonth?
According to your code logic it is nullable, and it appears that it might be a struct, so does this work?
if (model.SelectedMonth.HasValue)
{
contribs = contribs.Where(x => x.Date.Value.Month == model.SelectedMonth.Value);
}
You may need to create a Month OptionSet Attribute on your contrib Entity, which is populated via a plugin on the create/update of the entity for the Date Attribute. Then you could search by a particular month, and rather than searching a Date field, it's searching an int field. This would also make it easy to search for a particular month in the advanced find.
The Linq to CRM Provider isn't a full fledged version of Linq. It generally doesn't support any sort of operation on the attribute in your where statement, since it has to be converted to whatever QueryExpressions support.

Call a Linq to SQL user defined function multiple times in one trip to the DB

I have a user defined function that takes 2 datetime parameters and returns a short.
I've added it to my Linq to Sql model, which means I have a function like below:
private short? Aqua_NumShopDays(System.Nullable<System.DateTime> start,
System.Nullable<System.DateTime> end)
So, my question is, how can I call this for multiple date pairs easily (in a LINQy type way) that causes only one trip to the database?
If needed instead of a list of dates, it would still be useful if the first parameter was fixed, and the second parameter was every value in a given range.
Best I've found so far is to create a table (or user function that creates one) that has a range of numbers, then use that in Linq-To-SQL, as below:
// NumberRange is my user defined function, that returns a table with all a row per number
// Here I take that number and calculate the date based on an offset from today
var test = from dayOffset in ARDC.NumberRange(1, 10)
select DateTime.Today.AddDays(dayOffset.Counter.Value); // Counter is the column name of the table returned
// Using the dates, that are calculated on the server, I select a call to the SQL function
var testResults = from toDate in test
select ARDC.Aqua_NumShipDays(DateTime.Today, toDate).Value;
var t = testResults.ToList(); // This results in ONE trip to the database! (yay!)

How can i set sql date time with entity framework c#.net

I am very new to entity framework. Nice concept and fast as well.
Working in c#.net right now. I have stucked here where datetime comes in picture.
I mean....
lets assume i have user table in DB where CreatedDate fields is there in with datetime datatype in sql db.
My entity framework works like this...
when i need to add object to db, i simply pass objUser.createdDate = DateTime.now.
How ever I want to change the concept for some requirement changes.
I need to store sql server DateTime() for createdDate field in table.
How can i do that???
any idea...please help.
follwoing is a just sample code of my project.
objCustomer.RegisterDate = DateTime.Now;
objCustRepository.AddCustomer(objCustomer);
I want to remove this DateTime.Now line and maintain through sql....
if you can store the value from stored procedure instead of your business logic then you can try it by following.
to store SQL Datetime value then you can also use GETDATE() function in SQL.
or
you can define RegisterDate default value = GETDATE()
It sounds like you are trying to target the specific timezone associated with your sql server, if I am not mistaken?
If so why not use DateTimeOffset.Now via your c# when setting the date.
See this blog post here about the type.
A DateTimeOffset represents a specific point in time, so you can use it to convert to any timezone representation you may need on your UI.
Be aware though that it is only supported on SQL Server 2008 and greater, if I remember correctly. :)

Categories

Resources