2009-06-18 8 views
1

J'ai un problème étrange lors de la suppression d'enregistrements en utilisant linq, mon soupçon est qu'il a quelque chose à voir avec la variable de plage (nommé source). Après la suppression d'un enregistrement toutes les cibles pour un client sont récupérés à l'aide de la déclaration suivante:linq 'variable variable' problème

var q = from source in unitOfWork.GetRepository<db_Target>().Find() 
    where source.db_TargetBase.db_Person.fk_Customer == customerID 
    select source.FromLinq(); 

où FromLinq est dans la méthode extention sur db_target:

public static Target FromLinq(this db_Target source) 
{ 
    return new Target 
    { 
     id = source.id, 
     LastModified = source.db_TargetBase.LastModified, 
     ... 
    } 
} 

Lorsqu'un enregistrement est supprimé à la fois db_Target et db_TargetBase sont supprimés . Lorsque, par exemple, deux utilisateurs suppriment des enregistrements, linq essaie de récupérer un enregistrement pour user2 qui est supprimé par user1, provoquant un plantage sur la ligne LastModified = source.db_TargetBase.LastModified car db_TargetBase est null.

Lorsque vous utilisez le code suivant le problème n'occure et que les enregistrements non supprimés sont récupérés:

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

Ce engende deux questions:

  1. Qu'est-ce qui se passe ici? Est-ce que je fais une copie de la variable de plage source parce que je l'utilise dans une méthode de prolongation?
  2. Comment est-ce que je peux "envelopper" le code return new Target? Je l'utilise à plusieurs endroits et je ne veux pas le copier à chaque fois. Rendre mon code plus difficile à maintenir.

TIA,

JJ

Répondre

1

Dans le premier ensemble de code - puisque la initialiseur vit une méthode non-traduisible (extension ou autre), il ne peut pas être traduit - il est géré localement .

Dans le deuxième ensemble de code - l'initialiseur est représenté par une expression elementinit, qui est traduite (examiner/comparer la clause select du sql généré pour la preuve).


si vous voulez envelopper, vous devez avoir un Expression<Func<db_Target, Target>> que tout le monde peut saisir et utiliser dans Thier requête. Heureusement, c'est facile à faire:

public Expression<Func<db_Target, Target>> GetFromLinqExpressionForTarget() 
{ 
    return 
    source => new Target 
    { 
     id = source.id, 
     LastModified = source.db_TargetBase.LastModified, 
     ... 
    } 
} 

qui peut être utilisé comme ceci:

var FromLinq = GetFromLinqExpressionForTarget(); 
var q = 
(
    from source in ... 
    ... 
    ... 
    select source 
).Select(FromLinq); 

maintenant ... Je suis vraiment en cours d'exécution sur une supposition ici et je suis seulement 60% que mon la réponse est correcte. Donc, si quelqu'un veut confirmer cela, cela fera ma journée. :)

+0

Merci pour le respone, votre explication me semble parfaitement logique. Je suis en vacances maintenant, mais quand j'aurai le temps, je vais tester la mise en œuvre et donner les commentaires appropriés. – user124936