0

I have one view (vw_users) and one table (CTUsers). My sql query used to work when I was requesting data from the view:

var result = (from i in dc.vw_Users
              where i.CTid == ctid 
              select new 
              { 
                  UserId = i.UserId,  
                  WelcomeSent = (i.WelcomeSent != null && i.WelcomeSent.ToString().Length > 0 
                                ? DateTime.Parse(i.WelcomeSent.ToString()) 
                                 : new DateTime())
              });

But now I want to fetch the WelcomeSent from the table so I use this code:

var result = (from i in dc.vw_Users 
              join k in dc.CTUsers 
              on i.CTid equals k.CTid 
              where i.CTid == ctid 
              select new 
              { 
                  UserId = i.UserId, 
                  WelcomeSent = (k.WelcomeSent != null && k.WelcomeSent.ToString().Length > 0 
                                 ? DateTime.Parse(k.WelcomeSent.ToString()) 
                                 : new DateTime()) 
              }).Distinct();

But now when I run this query I get back this error:

SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM

The SQL view and table WelcomeSent type is DateTime and it can be NULL also. Here is an example value of WelcomeSent: 2017-03-07 00:00:00.000

nvoigt
  • 75,013
  • 26
  • 93
  • 142
atroul
  • 51
  • 1
  • 13
  • 5
    You know that visual studio supports multiple lines?! – Tim Schmelter Mar 13 '17 at 15:09
  • I dont understand how this comment is relevant – atroul Mar 13 '17 at 15:12
  • 2
    A little effort to format your code will help you to get answers. Reading a 879 char line about a total unknow problem is really difficult for any answerers. The comment above is really relevant. – Steve Mar 13 '17 at 15:12
  • 1
    I almost wanted to take the time to format it, but its just too much – EpicKip Mar 13 '17 at 15:14
  • ok I didnt get it... I removed most of the fields. – atroul Mar 13 '17 at 15:16
  • I think it is the final Distinct that creates the problem when you hit the condition that requires the _new DateTime()_ – Steve Mar 13 '17 at 15:18
  • The issue is with `new DateTime()`. that will give value `01/01/0001 12:00:00 AM` which is not valid datetime value as per the error description. – Chetan Mar 13 '17 at 15:18
  • Without the Distinct it was returning many duplicate lines, thats why I used it – atroul Mar 13 '17 at 15:19
  • 1
    Then change the empty new DateTime to new DateTime(1753,1,1) – Steve Mar 13 '17 at 15:19
  • @ChetanRanpariya but why it was working in the 1st case? without the join – atroul Mar 13 '17 at 15:20
  • You can put another condition in where `i.WelcomeSent != null`. That will not return the rows which has null in WelcomSent column. And why you need to convert the date value to string and then again parse the string to DateTime? You should simply assign whatever values is coming from the db to the property `WelcomeSent`. – Chetan Mar 13 '17 at 15:21
  • @Steve what I want is that if k.WelcomeSent is null then return a null value – atroul Mar 13 '17 at 15:21
  • Then why you need to check for null value? Just assign it to the target property.. you will get whatever value (NULL or DateTime) is there in the column to the property. – Chetan Mar 13 '17 at 15:24
  • Why is the `datetime` stored as a string in the database at all? Or, if it's already a `dateTime`, why don't you return it as `NULL`. You don't need such strange conversion overkills: `DateTime.Parse(i.WelcomeSent.ToString()) ` if `WelcomeSent` is already a `DateTime`. – Tim Schmelter Mar 13 '17 at 15:26
  • I had this problem thats why I used that conversion http://stackoverflow.com/questions/42694344/datecolumn-unable-to-cast-object-of-type-system-datetime-to-type-system-stri?noredirect=1#comment72514543_42694344 – atroul Mar 13 '17 at 15:30
  • does view `vw_Users` have any row with NULL in `WelcomSent` column? – Chetan Mar 13 '17 at 15:39
  • @ChetanRanpariya yes, many – atroul Mar 13 '17 at 15:41
  • A few questions: 1. Do you get the error even when you don't use Distinct clause? 2. Is there a datatype (datetime and datetime2) difference between WelcomeSent column of view and table? 3. Is it possible to share the generated sql queries in both the cases which is finally executed on the db? you can get it using sql profiler. 4. The table too have rows with NULL values in WelcomeSent column? – Chetan Mar 13 '17 at 15:50
  • @ChetanRanpariya 1.yes , 2.no they are both DateTime 3. Sorry I m not allowed. 4. yes – atroul Mar 13 '17 at 16:36
  • @atroul The issue is with the `Distinct` method in the LINQ to SQL. You can go thru the solution I suggested and see if that fits your requirement – Chetan Mar 15 '17 at 16:51

1 Answers1

0

The real issue here is the Distinct() method. If you get hold of the queries being run in SQL format and run directly on the db from SSMS they will run fine. It's the LINQ to SQL which have restriction of not allowing DateTime value less than certain value while using Distinct().

I am not sure why you need to use the weird to and fro conversion between datetime and string values.

Following are the actual queries which run on database.

First case :

SELECT [t0].[Id] AS [TokenId], [t0].[Token],     
(CASE WHEN ([t0].[ExpiryDate] IS NOT NULL) 
            AND ((CONVERT(Int,LEN(CONVERT(NVarChar(MAX),[t0].[ExpiryDate])))) > @p1) 
        THEN 1        
      WHEN NOT (([t0].[ExpiryDate] IS NOT NULL) 
            AND ((CONVERT(Int,LEN(CONVERT(NVarChar(MAX),[t0].[ExpiryDate])))) > @p1)) 
        THEN 0 
      ELSE NULL     
 END) AS [value], 
 CONVERT(NVarChar(MAX),[t0].[ExpiryDate]) AS [s] 
 FROM [dbo].[TokenView] AS [t0]WHERE [t0].[Id] = @p0

Second Case :

SELECT DISTINCT [t2].[Id] AS [TokenId], [t2].[Token], [t2].[value], [t2].[value2] AS [s], [t2].[value3]
FROM (    
    SELECT [t0].[Id], [t0].[Token], 
    (CASE WHEN ([t1].[ExpiryDate] IS NOT NULL) 
                AND ((CONVERT(Int,LEN(CONVERT(NVarChar(MAX),[t1].[ExpiryDate])))) > @p0) 
            THEN 1            
          WHEN NOT (([t1].[ExpiryDate] IS NOT NULL) 
                    AND ((CONVERT(Int,LEN(CONVERT(NVarChar(MAX),[t1].[ExpiryDate])))) > @p0))
            THEN 0            
          ELSE NULL         
    END) AS [value], 
    CONVERT(NVarChar(MAX),[t1].[ExpiryDate]) AS [value2], @p1 AS [value3]    
FROM [dbo].[TokenView] AS [t0]    
    INNER JOIN [dbo].[Tokens] AS [t1] ON [t0].[Id] = [t1].[Id]) AS [t2]
WHERE [t2].[Id] = @p2

I would suggest following solution for the second query to resolve the issue.

Create a class which can hold the data you select from the database using query.

public class MyClass
{
    public int Id { get; set; }

    public string Token { get; set; }

    //Consider this property as WelcomeSent property from your code.
    public DateTime? ExpiryDate { get; set; }

    //Use this property only to display the data in UI.
    public DateTime FormattedExpiryDate
    {
        get
        {
            return ExpiryDate != null && ExpiryDate.ToString().Length > 0
                                        ? DateTime.Parse(ExpiryDate.ToString())
                                         : new DateTime();
        }
    }
} 

Change the query as following.

var query = (from i in dc.TokenViews //TokenViews is same as vw_Users of yours.
                     join k in dc.Tokens //Tokens is same as CTUsers
                     on i.Id equals k.Id
                     where i.Id == 5 //Hardcoding the selection criteria. 
                     select new MyClass
                     {
                         Id = i.Id,
                         Token = i.Token,
                         ExpiryDate = k.ExpiryDate //Retrieving values as it is from the db.
                      }).Distinct();

Display the value as following to see the different between ExpiryDate and FormattedExpiryDate

foreach (var item in query)
{
    Console.WriteLine("Id : {0}", item.Id);
    Console.WriteLine("Token : {0}", item.Token);
    Console.WriteLine("ExpiryDate : {0}", item.ExpiryDate);
    Console.WriteLine("FormattedDate : {0}", item.FormattedExpiryDate);
}

You can use the same approach for the first query too. This will avoid all the CASE WHEN clauses and CONVERTs in the SQL query.

Chetan
  • 6,711
  • 3
  • 22
  • 32