Posso projetar uma referência opcional de uma entidade em uma referência opcional do tipo de resultado da projeção?

Diga, eu tenho duas entidades:

public class Customer
{
    public int Id { get; set; }
    public int SalesLevel { get; set; }
    public string Name { get; set; }
    public string City { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public DateTime DueDate { get; set; }
    public string ShippingRemark { get; set; }

    public int? CustomerId { get; set; }
    public Customer Customer { get; set; }
}

Customer é umopcional (anulável) referência emOrder (talvez o sistema suporte pedidos "anônimos").

Agora, quero projetar algumas propriedades de um pedido em um modelo de exibição, incluindo algumas propriedades do clienteE se o pedido tem um cliente. Eu tenho duas classes de modelos de visão, em seguida:

public class CustomerViewModel
{
    public int SalesLevel { get; set; }
    public string Name { get; set; }
}

public class OrderViewModel
{
    public string ShippingRemark { get; set; }
    public CustomerViewModel CustomerViewModel { get; set; }
}

Se oCustomer seria umrequeridos propriedade de navegação emOrder Eu poderia usar a seguinte projeção e funciona porque eu posso ter certeza que umCustomer sempre existe para qualquerOrder:

OrderViewModel viewModel = context.Orders
    .Where(o => o.Id == someOrderId)
    .Select(o => new OrderViewModel
    {
        ShippingRemark = o.ShippingRemark,
        CustomerViewModel = new CustomerViewModel
        {
            SalesLevel = o.Customer.SalesLevel,
            Name = o.Customer.Name
        }
    })
    .SingleOrDefault();

Mas isso não funciona quandoCustomer é opcional e o pedido com o IDsomeOrderId não tem cliente:

A EF reclama que o valor materializado parao.Customer.SalesLevel éNULL e não pode ser armazenado nointPropriedade não anulávelCustomerViewModel.SalesLevel. Isso não é surpreendente e o problema poderia ser resolvido fazendoCustomerViewModel.SalesLevel do tipoint? (ou geralmentetodos propriedades anuláveis)

Mas eu realmente preferiria issoOrderViewModel.CustomerViewModel é materializado comonull quando o pedido não tem cliente.

Para conseguir isso, tentei o seguinte:

OrderViewModel viewModel = context.Orders
    .Where(o => o.Id == someOrderId)
    .Select(o => new OrderViewModel
    {
        ShippingRemark = o.ShippingRemark,
        CustomerViewModel = (o.Customer != null)
            ? new CustomerViewModel
              {
                  SalesLevel = o.Customer.SalesLevel,
                  Name = o.Customer.Name
              }
            : null
    })
    .SingleOrDefault();

Mas isso lança a infame exceção LINQ to Entities:

Não é possível criar um valor constante do tipo 'CustomerViewModel'. Apenas tipos primitivos (por exemplo, 'Int32', 'String' e 'Guid' ') são suportados neste contexto.

eu acho que: null é o "valor constante" paraCustomerViewModel o que não é permitido.

Desde a atribuiçãonull não parece ser permitido eu tentei introduzir uma propriedade de marcador emCustomerViewModel:

public class CustomerViewModel
{
    public bool IsNull { get; set; }
    //...
}

E então a projeção:

OrderViewModel viewModel = context.Orders
    .Where(o => o.Id == someOrderId)
    .Select(o => new OrderViewModel
    {
        ShippingRemark = o.ShippingRemark,
        CustomerViewModel = (o.Customer != null)
            ? new CustomerViewModel
              {
                  IsNull = false,
                  SalesLevel = o.Customer.SalesLevel,
                  Name = o.Customer.Name
              }
            : new CustomerViewModel
              {
                  IsNull = true
              }
    })
    .SingleOrDefault();

Isso também não funciona e lança a exceção:

O tipo 'CustomerViewModel' aparece em duas inicializações incompatíveis estruturalmente dentro de uma única consulta LINQ to Entities. Um tipo pode ser inicializado em dois locais na mesma consulta, mas apenas se as mesmas propriedades estiverem definidas nos dois locais e essas propriedades forem definidas na mesma ordem.

A exceção é clara o suficiente para corrigir o problema:

OrderViewModel viewModel = context.Orders
    .Where(o => o.Id == someOrderId)
    .Select(o => new OrderViewModel
    {
        ShippingRemark = o.ShippingRemark,
        CustomerViewModel = (o.Customer != null)
            ? new CustomerViewModel
              {
                  IsNull = false,
                  SalesLevel = o.Customer.SalesLevel,
                  Name = o.Customer.Name
              }
            : new CustomerViewModel
              {
                  IsNull = true,
                  SalesLevel = 0, // Dummy value
                  Name = null
              }
    })
    .SingleOrDefault();

Isso funciona, mas não é uma solução muito boa para preencher todas as propriedades com valores fictícios ounull explicitamente.

Questões:

É o último código trecho a única solução, além de fazer todas as propriedades doCustomerViewModel anulável?

Simplesmente não é possível materializar uma referência opcional paranull em uma projeção?

Você tem uma ideia alternativa de como lidar com essa situação?

(Eu estou apenas definindo o geralEstrutura de entidade tag para esta pergunta porque eu acho que esse comportamento não é específico da versão, mas não tenho certeza. Eu testei os trechos de código acima com EF 4.2 /DbContext/ Código-primeiro. Editar: mais duas tags adicionadas.

questionAnswers(1)

yourAnswerToTheQuestion