2009-06-18 11 views
1

Ich habe ein seltsames Problem beim Löschen von Datensätzen mit Linq, mein Verdacht ist, dass es etwas mit der Bereichsvariable (mit dem Namen source) zu tun hat. Nach dem Löschen werden eine Aufzeichnung alle Ziele für einen Kunden die folgende Anweisung abgerufen werden:linq 'Bereich Variable' Problem

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

wo FromLinq in extention Verfahren auf db_target ist:

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

Wenn ein Datensatz gelöscht wird sowohl db_Target und db_TargetBase gelöscht . Wenn z. B. zwei Benutzer Datensätze löschen, versucht linq, einen Datensatz für Benutzer2 abzurufen, der von Benutzer1 gelöscht wird, was zu einem Absturz in der Zeile LastModified = source.db_TargetBase.LastModified führt, da db_TargetBasenull ist.

Wenn mit dem folgenden Code das Problem nicht und nur die nicht-gelöschten Datensätze abgerufen werden, nicht occure:

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

Dieser laicht zwei Fragen:

  1. Was hier geschieht? Mache ich eine Kopie der Bereichsvariablen source, weil ich sie in einer Erweiterungsmethode verwende?
  2. Wie kann ich den return new Target Code "wickeln"? Ich verwende das an mehreren Stellen und möchte es nicht jedes Mal kopieren. Der Code wird schwerer zu warten.

TIA,

JJ

Antwort

1

Im ersten Satz von Code - da der Initialisierer eine eine nicht übersetzbar Methode (Erweiterung oder auf andere Weise) lebt, kann sie nicht übersetzt werden - so dass es lokal ausgeführt wird .

Im zweiten Satz von Code - der Initialisierer wird durch einen elementinit Ausdruck dargestellt, der übersetzt wird (untersuchen/vergleichen Sie die SELECT-Klausel der generierten SQL für den Beweis).


, wenn Sie diese wickeln möchten, benötigen Sie einen Expression<Func<db_Target, Target>> haben, dass jemand packen und in thier Abfrage verwenden können. Zum Glück, das zu tun, ist einfach:

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

, die wie so verwendet werden können:

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

Nun ... ich wirklich auf einer Vermutung renne hier und sind nur etwa 60% davon überzeugt, dass mein Antwort ist richtig. Wenn also jemand das bestätigen will, wird das meinen Tag ausmachen. :)

+0

Danke für die Antwort, Ihre Erklärung macht für mich vollkommen Sinn. Ich bin gerade im Urlaub, aber wenn ich Zeit habe, werde ich die Implementierung testen und das entsprechende Feedback geben. – user124936