Beachten:
1. Die in diesem Artikel erwähnten „Entitäten“ werden alle von LINQ TO SQL (d. h. .dbml) generiert.
2. Sie müssen verstehen, wie LINQ TO SQL die Tabellenzuordnungen EntitySet und EntityRef implementiert
Nachdem Sie den Titel gelesen haben, werden Sie vielleicht denken, dass die Frage relativ abstrakt ist. Lassen Sie mich daher ein Beispiel geben, um das Problem im Detail zu erläutern.
Wenn wir in der N-Tier-Architektur auf Basis von LINQ TO SQL eine Entität aktualisieren müssen, sollte der Prozess wie folgt ablaufen:
Verfahren
BLL.GetModel(p=>p.id==1) -> Ändern Sie den entsprechenden Attributwert (Feldwert) -> BLL.Update(Entity-Entität) -> DAL.Update(Entity-Entität) -> Aktualisierung erfolgreich
Zu diesem Zeitpunkt müssen wir diese Entität von der Business-Schicht (BLL) an die Datenzugriffsschicht (DAL) übergeben. Wenn die GetModel-Methode die Entität zurückgibt, wird der DataContext sofort freigegeben und beim DAL erneut instanziiert. Die Methode „Update“ (Entität) wird ausgeführt. Erstellen Sie einen DataContext, um den Aktualisierungsvorgang durchzuführen. Es ist ersichtlich, dass die übergebene Entität vom ersten DataContext an einen anderen DataContext übergeben wird zuerst ausgeführt werden, das heißt context.Entity. Attach(entity,true); Schließlich context.SubmitChanges();
Werfen wir einen Blick auf den Code:
Code
Klasse BLL
{
private readonly DAL dal = new DAL();
public LinqToSqlProvider.User GetModel(Expression<Func<LinqToSqlProvider.User, bool>> expression)
{
dal.GetModel(expression);
}
public void Update(LinqToSqlProvider.User-Entität)
{
dal.Update(entity);
}
}
Klasse DAL
{
public LinqToSqlProvider.User GetModel(Expression<Func<LinqToSqlProvider.User, bool>> expression)
{
LinqToSqlProvider.User-Eintrag = new CriTextBroadcast.LinqToSqlProvider.User();
mit (CriTextBroadcastDBDataContext context = DataContext)
{
Eintrag = context.User.SingleOrDefault(expression);
}
Rückfahrt;
}
public void Update(LinqToSqlProvider.User-Entität)
{
mit (CriTextBroadcastDBDataContext context = DataContext)
{
context.User.Attach(entry, true);
context.SubmitChanges();
}
}
}
Wenn wir den obigen Code zum Betrieb verwenden, tritt tatsächlich diese Ausnahme auf:
Es wurde versucht, eine Entität anzuhängen oder hinzuzufügen. Diese Entität ist keine neue Entität, kann aus einem anderen DataContext geladen werden ...
Nachdem ich viele Informationen vergeblich überprüft hatte, sah ich schließlich eine ähnliche Frage in einem ausländischen Beitrag. Es stellt sich heraus, dass die dieser Entität entsprechende Tabelle mehrere verwandte Tabellen enthält, z. B.: Benutzer -> Nachricht, Benutzer -> Bilder usw.
Attribute wie EntitySet<Message> Message werden beim Generieren von Entitätsklassen automatisch generiert. Da wir diese zugehörigen Inhalte beim Abrufen der Entität nicht zusammen auslesen, tritt beim Anhängen (Attach) eine ObjectDisposedException auf zur Abfrage dieser Entität verwendet wurde, wurde freigegeben.
Lösung:
Code
/// <Zusammenfassung>
/// Die zusätzliche LinqToSql-Entität wird vom ursprünglichen DataContext getrennt
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entity"></param>
public static void Detatch<TEntity>(TEntity-Entität)
{
Typ t = entity.GetType();
System.Reflection.PropertyInfo[] Properties = t.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach (Var-Eigenschaft in Eigenschaften)
{
string name = property.Name;
if (property.PropertyType.IsGenericType &&
property.PropertyType.GetGenericTypeDefinition() == typeof(EntitySet<>))
{
property.SetValue(entity, null, null);
}
}
System.Reflection.FieldInfo[] Felder = t.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
foreach (Var-Feld in Feldern)
{
string name = field.Name;
if (field.FieldType.IsGenericType &&
field.FieldType.GetGenericTypeDefinition() == typeof(EntityRef<>))
{
field.SetValue(entity, null);
}
}
System.Reflection.EventInfo eventPropertyChanged = t.GetEvent("PropertyChanged");
System.Reflection.EventInfo eventPropertyChanging = t.GetEvent("PropertyChanging");
if (eventPropertyChanged != null)
{
eventPropertyChanged.RemoveEventHandler(entity, null);
}
if (eventPropertyChanging != null)
{
eventPropertyChanging.RemoveEventHandler(entity, null);
}
}
Nachdem Sie die Entität erhalten haben, sollten Sie die Detach(entity)-Methode verwenden, um die Entität vom ursprünglichen DataContext zu trennen und sie dann an den neuen DataContext anzuhängen.