dire che ho due entità:Posso proiettare un riferimento facoltativo di un'entità in un riferimento facoltativo del tipo di risultato della proiezione?
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
è un optional (nullable) di riferimento in Order
(forse il sistema supporta gli ordini "anonimi").
Ora, desidero proiettare alcune proprietà di un ordine in un modello di vista che include alcune proprietà del cliente se l'ordine ha un cliente. Ho due classi di vista del modello poi:
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 il Customer
sarebbe una richiesta di proprietà navigazione in Order
ho potuto utilizzare il seguente proiezione e funziona perché posso essere sicuro che un Customer
esiste sempre per qualsiasi 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();
Ma questo non funziona quando Customer
è facoltativo e l'ordine con ID someOrderId
non avere un cliente:
EF lamenta che il valore materializzato per
o.Customer.SalesLevel
èNULL
e non può essere memorizzato nelint
, non di proprietà nullableCustomerViewModel.SalesLevel
. Questo non è sorprendente e il problema potrebbe essere risolto facendoCustomerViewModel.SalesLevel
di tipoint?
(o in generale tutti i proprietà nullable)Ma vorrei in realtà preferirei che
OrderViewModel.CustomerViewModel
si materializza comenull
quando l'ordine è nessun cliente.
per raggiungere questo obiettivo ho provato quanto segue:
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();
Ma questo getta il LINQ famigerato ad eccezione Entità:
Impossibile creare un valore costante di tipo 'CustomerViewModel'. Solo i tipi primitivi (ad esempio '' Int32 ',' String 'e' Guid '') sono supportati in questo contesto .
Immagino che : null
sia il "valore costante" per CustomerViewModel
che non è consentito.
Dal assegnazione null
non sembra essere permesso ho cercato di introdurre una proprietà marcatore in CustomerViewModel
:
public class CustomerViewModel
{
public bool IsNull { get; set; }
//...
}
E poi la proiezione:
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();
Questo non funziona neanche e getta l'eccezione:
Il tipo "CustomerViewModel" viene visualizzato in due str Inizializzazioni iniziali incompatibili all'interno di una singola query LINQ to Entities. Un tipo può essere inizializzato in due posizioni nella stessa query, ma solo se le stesse proprietà sono impostate in entrambe le posizioni e tali proprietà sono impostate nello stesso ordine .
L'eccezione è abbastanza chiaro come risolvere il 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();
Questo funziona, ma non è una bella soluzione per riempire tutte le proprietà con i valori fittizi o null
esplicitamente.
Domande:
è l'ultimo frammento di codice l'unica soluzione, oltre a fare tutte le proprietà del
CustomerViewModel
annullabile?Semplicemente non è possibile materializzare un riferimento facoltativo a
null
in una proiezione?Avete un'idea alternativa su come affrontare questa situazione?
(sto unica impostazione generale entità-quadro tag per questa domanda, perché credo che questo comportamento non è la versione specifica, ma non sono sicuro. Ho testato i frammenti di codice di cui sopra con EF 4.2/DbContext
/Code-First Modifica: Altri due tag aggiunti.)
Hai mai trovato una soluzione per questo? e se fosse così ti dispiacerebbe condividere :) –
@QuintonBernhardt: No, non ho trovato una soluzione. Risolvo questo principalmente rendendo annullabili tutte le proprietà del modello di visualizzazione annidate. – Slauma