Os argumentos DbArithmeticExpression devem ter um tipo numérico comum

120
TimeSpan time24 = new TimeSpan(24, 0, 0);
TimeSpan time18 = new TimeSpan(18, 0, 0);    

// first get today's sleeping hours
List<Model.Sleep> sleeps = context.Sleeps.Where(
    o => (clientDateTime - o.ClientDateTimeStamp < time24) && 
          o.ClientDateTimeStamp.TimeOfDay > time18 && 
          clientDateTime.TimeOfDay < time18 && 
          o.UserID == userid).ToList(); 

Esta expressão Linq lança esta exceção:

DbArithmeticExpression arguments must have a numeric common type.

Por favor ajude!

Nawaz Dhandala
fonte
Qual é o resultado clientDateTime - o.ClientDateTimeStamp?
shahkalpesh
normalmente isso deve ser um objeto do TimeSpan, no EF a exceção é lançada.
Nawaz Dhandala,

Respostas:

247

Aritmética com DateTimenão é compatível com o Entity Framework 6 e anteriores. Você deve usar DbFunctions *. Então, para a primeira parte de sua declaração, algo como:

var sleeps = context.Sleeps(o =>
    DbFunctions.DiffHours(o.ClientDateTimeStamp, clientDateTime) < 24);

Observe que o DiffHoursmétodo aceita Nullable<DateTime>.

O núcleo do Entity Framwork (quando usado com o Sql Server, talvez outros provedores de banco de dados) suporta as AddXxxfunções DateTime (como AddHours). Eles são traduzidos paraDATEADD em SQL.

* EntityFunctionsantes do Entity Framework versão 6.

Gert Arnold
fonte
2

Eu sei que esta é uma questão antiga, mas no seu caso específico, em vez de usar DBFunctions como sugerido por @GertArnold, você não poderia simplesmente inverter a operação e retirar a aritmética em questão do Lambda?

Afinal, clientDateTimee time24são valores fixos para que sua diferença não precise ser recalculada a cada iteração.

Gostar:

TimeSpan time24 = new TimeSpan(24, 0, 0);
TimeSpan time18 = new TimeSpan(18, 0, 0);    

var clientdtminus24 = clientDateTime - time24;

// first get today's sleeping hours
List<Model.Sleep> sleeps = context.Sleeps.Where(
    o => (clientdtminus24 < o.ClientDateTimeStamp) && 
          o.ClientDateTimeStamp.TimeOfDay > time18 && 
          clientDateTime.TimeOfDay < time18 && 
          o.UserID == userid).ToList();

Essa refatoração geralmente é possível se você estiver tentando comparar a data e hora armazenada alterada por um carimbo de data / hora fixo com uma outra data e hora.

SoonDead
fonte
Eu tive essa mesma situação, e isso ajudou. No entanto, o escopo dessa solução é muito limitado a um tipo específico de problema.
Zimano
@Zimano Resolve o problema de OPs sem exigir que ele mude de tecnologia ou recorra a hacks. Se ele puder ser refatorado assim, faça-o; se não, faça como na resposta aceita.
SoonDead
1

Por outro lado, se o desempenho não for o verdadeiro objetivo, você pode tentar usar AsEnumerable(). Então, seria como

List<Model.Sleep> sleeps = context.Sleeps.AsEnumerable().Where(....

Adicionar AsEnumerable () converterá a consulta SQL em entidade e permitirá executar funções .Net nelas. Para obter mais informações, verifique aqui sobre AsEnumerable

bagunçado
fonte