Могу ли я проецировать необязательную ссылку на сущность в необязательную ссылку типа результата проекции?

Скажем, у меня есть две сущности:

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 являетсяoptional (обнуляемая) ссылка вOrder (возможно, система поддерживает «анонимные» заказы).

Теперь я хочу спроецировать некоторые свойства заказа в модель представления, включая некоторые свойства клиента.if заказ есть у клиента. У меня есть два вида моделей моделей:

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

ЕслиCustomer будетrequired свойство навигации вOrder Я мог бы использовать следующую проекцию, и она работает, потому что я могу быть уверен, чтоCustomer всегда существует для любогоOrder:

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

Но это не работает, когдаCustomer необязательно и заказ с IdsomeOrderId не имеет клиента:

EF complains that the materialized value for o.Customer.SalesLevel is NULL and cannot be stored in the int, not nullable property CustomerViewModel.SalesLevel. That's not surprising and the problem could be solved by making CustomerViewModel.SalesLevel of type int? (or generally all properties nullable)

But I would actually prefer that OrderViewModel.CustomerViewModel is materialized as null when the order has no customer.

Чтобы добиться этого, я попробовал следующее:

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

Но это бросает печально известное исключение LINQ to Entities:

Unable to create a constant value of type 'CustomerViewModel'. Only primitive types (for instance ''Int32', 'String' und 'Guid'') are supported in this context.

я думаю что: null является «постоянным значением»; заCustomerViewModel что не разрешено.

С момента назначенияnull кажется, не разрешено, я пытался ввести свойство маркера вCustomerViewModel:

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

А потом проекция:

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

Это тоже не работает и выдает исключение:

The type 'CustomerViewModel' appears in two structurally incompatible initializations within a single LINQ to Entities query. A type can be initialized in two places in the same query, but only if the same properties are set in both places and those properties are set in the same order.

Исключение достаточно понятно, как решить проблему:

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

Это работает, но это не очень хороший обходной путь, чтобы заполнить все свойства фиктивными значениями илиnull в явном виде.

Вопросы:

Is the last code snippet the only workaround, aside from making all properties of the CustomerViewModel nullable?

Is it simply not possible to materialize an optional reference to null in a projection?

Do you have an alternative idea how to deal with this situation?

(Я только устанавливаю общиеentity-framework тег для этого вопроса, потому что я думаю, что это поведение не зависит от версии, но я не уверен. Я тестировал фрагменты кода выше с EF 4.2 /DbContext/ Code-первых. Изменить: добавлены еще два тега.)

Ответы на вопрос(1)

Ваш ответ на вопрос