Czy mogę rzutować opcjonalne odniesienie jednostki na opcjonalne odniesienie typu wyniku projekcji?

Powiedz, mam dwie jednostki:

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 jestopcjonalny (dopuszczalna) odwołanie wOrder (może system obsługuje zamówienia „anonimowe”).

Teraz chcę wyświetlić niektóre właściwości zamówienia w modelu widoku, w tym niektóre właściwości klientaJeśli zamówienie ma klienta. Mam wtedy dwie klasy modelu widoku:

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; }
}

JeśliCustomer byłoby awymagany właściwość nawigacji wOrder Mogłem użyć następującej projekcji i działa, ponieważ mogę być pewien, że aCustomer zawsze istnieje dla każdegoOrder:

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();

Ale to nie działa, kiedyCustomer jest opcjonalne, a zamówienie z IdsomeOrderId nie ma klienta:

EF skarży się na zmaterializowaną wartośćo.Customer.SalesLevel jestNULL i nie mogą być przechowywane wint, nie dopuszczalna wartośćCustomerViewModel.SalesLevel. Nie jest to zaskakujące, a problem można rozwiązaćCustomerViewModel.SalesLevel typuint? (lub ogólniewszystko właściwości dopuszczalne)

Ale wolałbym toOrderViewModel.CustomerViewModel jest zmaterializowany jakonull kiedy zamówienie nie ma klienta.

Aby to osiągnąć, spróbowałem:

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();

Ale to powoduje niesławny wyjątek LINQ to Entities:

Nie można utworzyć stałej wartości typu „CustomerViewModel”. W tym kontekście obsługiwane są tylko typy prymitywne (na przykład „Int32”, „String” i „Guid”).

zgaduję, że: null jest „stałą wartością”CustomerViewModel co jest niedozwolone.

Od momentu przypisanianull nie wydaje się być dozwolone Próbowałem wprowadzić właściwość znacznika wCustomerViewModel:

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

A potem projekcja:

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();

To również nie działa i zgłasza wyjątek:

Typ „CustomerViewModel” pojawia się w dwóch strukturalnie niezgodnych inicjalizacjach w ramach pojedynczego zapytania LINQ to Entities. Typ można zainicjować w dwóch miejscach w tym samym zapytaniu, ale tylko wtedy, gdy te same właściwości są ustawione w obu miejscach, a te właściwości są ustawione w tej samej kolejności.

Wyjątek jest wystarczająco jasny, jak rozwiązać problem:

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();

To działa, ale nie jest to bardzo przyjemne obejście, aby wypełnić wszystkie właściwości wartościami atrapowymi lubnull jawnie.

Pytania:

Czy ostatni fragment kodu jest jedynym obejściem, oprócz tworzenia wszystkich właściwościCustomerViewModel nieważne?

Czy po prostu nie można zmaterializować opcjonalnego odniesienia donull w projekcji?

Czy masz alternatywny pomysł, jak poradzić sobie z tą sytuacją?

(Ustawiam tylko generałaramy podmiotu tag dla tego pytania, ponieważ myślę, że to zachowanie nie jest specyficzne dla wersji, ale nie jestem pewien. Testowałem fragmenty kodu powyżej z EF 4.2 /DbContext/ Code-First. Edytuj: dodano jeszcze dwa tagi.)

questionAnswers(1)

yourAnswerToTheQuestion