efcore: Nullable DateTime in projection class - System.Data.SqlClient.SqlException: 'Conversion failed when converting date and/or time from character string.'
Having a one to many relationship, the main entity can have zero to n child entities. When I want to select the main entity’s Id and most recent DateTime from the child entity collection, SQL execution crashes with a System.Data.SqlClient.SqlException
Exception message:
Conversion failed when converting date and/or time from character string
Stack trace:
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlDataReader.TryHasMoreRows(Boolean& moreRows)
at System.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean& more)
at System.Data.SqlClient.SqlDataReader.Read()
at Microsoft.EntityFrameworkCore.Storage.RelationalDataReader.Read()
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
at lambda_method(Closure )
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ResultEnumerable`1.GetEnumerator()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass15_1`1.<CompileQueryCore>b__0(QueryContext qc)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
at EfCoreErrReproduction.Program.Main()
SQL produced:
Executed DbCommand (57ms) [Parameters=[@__id_0='3422'], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [p].[Id], (
SELECT COUNT(*)
FROM [TicketNumberDelta] AS [t]
WHERE [p].[Id] = [t].[TicketNumberId]
) AS [DeltaCount], COALESCE((
SELECT TOP(1) [lx].[RecordTimeStamp]
FROM [TicketNumberDelta] AS [lx]
WHERE [p].[Id] = [lx].[TicketNumberId]
ORDER BY [lx].[RecordTimeStamp] DESC
), '0001-01-01T00:00:00.0000000') AS [LastEntry]
FROM [TicketNumber] AS [p]
WHERE [p].[Id] = @__id_0
System.Data.SqlClient.SqlException: 'Conversion failed when converting date and/or time from character string.'
Steps to reproduce
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
namespace EfCoreErrReproduction
{
class Program
{
static void Main(string[] args)
{
var db = new StrippedDownContext();
var crash = db.TicketNumbers.Where(p => p.Id == 3422).Select(p => new ProjectionClass
{
Id = p.Id,
DeltaCount = p.TicketNumberDeltas.Count(),
LastEntry = p.TicketNumberDeltas.OrderByDescending(lx => lx.RecordTimeStamp).Select(le => le.RecordTimeStamp).FirstOrDefault()
}).FirstOrDefault();
}
}
class ProjectionClass
{
public int Id { get; set; }
public int DeltaCount { get; set; }
public DateTime? LastEntry { get; set; }
}
}
namespace EfCoreErrReproduction
{
public class StrippedDownContext : DbContext
{
public StrippedDownContext()
{
}
public StrippedDownContext(DbContextOptions<StrippedDownContext> options)
: base(options)
{
}
public virtual DbSet<TicketNumber> TicketNumbers { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("db conn string");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TicketNumber>(entity =>
{
entity.ToTable("TicketNumber");
});
modelBuilder.Entity<TicketNumberDelta>(entity =>
{
entity.ToTable("TicketNumberDelta");
entity.HasOne(p => p.TicketNumber)
.WithMany(p => p.TicketNumberDeltas)
.HasForeignKey(p => p.TicketNumberId);
entity.Property(e => e.RecordTimeStamp).HasColumnType("datetime");
});
}
}
public class TicketNumber
{
public TicketNumber()
{
TicketNumberDeltas = new List<TicketNumberDelta>();
}
public int Id { get; set; }
public virtual ICollection<TicketNumberDelta> TicketNumberDeltas { get; set; }
}
public partial class TicketNumberDelta
{
public int Id { get; set; }
public int? TicketNumberId { get; set; }
public DateTime RecordTimeStamp { get; set; }
public virtual TicketNumber TicketNumber { get; set; }
}
}
Further technical details
EF Core version: 2.1.1 Database Provider: Microsoft.EntityFrameworkCore.SqlServer Operating system: Win 10 Enterprise x64 IDE: Visual Studio 2017 15.7.5
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 2
- Comments: 24 (21 by maintainers)
Commits related to this issue
- Query: Infer typemapping for ExpressionType.Coalesce Partial fix for #12797 — committed to dotnet/efcore by smitpatel 6 years ago
- Query: Infer typemapping for ExpressionType.Coalesce Partial fix for #12797 — committed to dotnet/efcore by smitpatel 6 years ago
- Query: Infer typemapping for ExpressionType.Coalesce Partial fix for #12797 — committed to dotnet/efcore by smitpatel 6 years ago
@brunolau workaround is to cast the
RecordTimeStamp
to nullableDateTime
before its projected, like so: