União EF 5 não funciona como esperado
-
11-12-2019 - |
Pergunta
Eu tenho uma consulta linq envolvendo as três entidades a seguir:
public class LandPoint
{
...
public OlsonTimeZone TimeZone { get; set; }
}
public class OlsonTimeZone : TimeZone
{
...
public virtual ICollection<WindowsTimeZone> Windows { get; set; }
}
public class WindowsTimeZone : TimeZone
{
...
public virtual ICollection<OlsonTimeZone> Olson { get; set; }
}
Portanto, um LandPoint possui um OlsonTimeZone que possui zero ou mais WindowsTimeZones.
O que estou tentando fazer é obter o nome WindowsTimeZone (prefixado por 'Windows:') se OlsonTimeZone tiver algum WindowsTimeZones ou o nome OlsonTimeZone (prefixado por 'Olson:') como um substituto junto com informações sobre o ponto em si.
O que escrevi é:
return db.LandPoints.Where(x => x.GeoNameID == ID).Take(1).Select(x => new LandPoint
{
TimeZone = x.TimeZone
.Windows.Select(t => "Windows:" + x.Name)
.Union(new[] { "Olson:" + x.TimeZone.Name })
.FirstOrDefault()
}).First();
O que deveria, em teoria, fazer o que eu quero.Exceto que, para um determinado ponto com o qual testei (que sei que tem um WindowsTimeZone associado), ele retornou OlsonTimeZone em vez de WindowsTimeZone.Se para o mesmo ID eu escrevo o seguinte:
return db.LandPoints.Where(x => x.GeoNameID == ID).Take(1).Select(x => new LandPoint
{
TimeZone = x.TimeZone
.Windows.Select(t => "Windows:" + x.Name)
.FirstOrDefault()
}).First();
Eu recebo o WindowsTimeZone.
Tenho certeza de que poderia reescrevê-lo usando uma instrução CASE, mas achei que era mais elegante.Como o modo como ele se comporta é um tanto contra-intuitivo e entender por que ele está fazendo o que faz me ajudaria a ter uma noção melhor de como as consultas linq são traduzidas para sql, decidi postar uma pergunta aqui.
Então, por que está fazendo o que faz?Existe alguma adição ao código acima que o faria funcionar (mantendo a instrução UNION)?
Desde já, obrigado John
Solução
É porque a união não garante a ordem.Você não pode colocar expectativas especiais com base na ordem dos itens sem encomendá-los.Mas seu código deve disparar NotSupportedException
porque isso não é permitido: db.LandPoints.Select(x => new LandPoint ...
Se você tem LandPoint
entidade mapeada pela estrutura de entidade, você não pode projetar para este tipo em Linq-to-entities.