problema "intervallo variabile" di linq
-
06-07-2019 - |
Domanda
Ho uno strano problema durante l'eliminazione dei record usando linq, il mio sospetto è che abbia qualcosa a che fare con la variabile range (chiamata source
). Dopo aver eliminato un record, tutte le destinazioni per un cliente vengono recuperate utilizzando la seguente dichiarazione:
var q = from source in unitOfWork.GetRepository<db_Target>().Find()
where source.db_TargetBase.db_Person.fk_Customer == customerID
select source.FromLinq();
dove FromLinq è nel metodo di estensione su db_target:
public static Target FromLinq(this db_Target source)
{
return new Target
{
id = source.id,
LastModified = source.db_TargetBase.LastModified,
...
}
}
Quando un record viene eliminato sia db_Target
che db_TargetBase
vengono eliminati. Quando, ad esempio, due utenti stanno eliminando record, linq tenta di recuperare un record per user2 che viene eliminato dall'utente1, causando un arresto anomalo sulla linea LastModified = source.db_TargetBase.LastModified
perché null
è return new Target
.
Quando si utilizza il seguente codice il problema non si verifica e vengono recuperati solo i record non eliminati:
var q = from source in unitOfWork.GetRepository<db_Target>().Find()
where source.db_TargetBase.db_Person.fk_Customer == customerID
select new Target
{
id = source.id,
LastModified = source.db_TargetBase.LastModified,
...
};
Questo genera due domande:
- Cosa sta succedendo qui? Sto facendo una copia della variabile di intervallo <=> perché la sto usando in un metodo di estensione?
- Come posso " avvolgere " il <=> codice? Lo sto usando in più punti e non voglio copiarlo ogni volta. Rendere il mio codice più difficile da mantenere.
TIA,
JJ
Soluzione
Nel primo set di codice - poiché l'inizializzatore utilizza un metodo non traducibile (estensione o altro), non può essere tradotto - quindi viene eseguito localmente.
Nel secondo set di codice, l'inizializzatore è rappresentato da un'espressione elementinit, che viene tradotta (esaminare / confrontare la clausola select del sql generato per la prova).
se vuoi concludere questo, devi avere un Expression<Func<db_Target, Target>>
che chiunque possa prendere e usare nella sua query. Fortunatamente, è facile da fare:
public Expression<Func<db_Target, Target>> GetFromLinqExpressionForTarget()
{
return
source => new Target
{
id = source.id,
LastModified = source.db_TargetBase.LastModified,
...
}
}
Che può essere usato in questo modo:
var FromLinq = GetFromLinqExpressionForTarget();
var q =
(
from source in ...
...
...
select source
).Select(FromLinq);
Ora ... sto davvero provando a indovinare qui e sono solo circa il 60% sicuro che la mia risposta sia corretta. Quindi, se qualcuno vuole confermarlo, questo renderà la mia giornata. :)