Entity Update in verteilten Szenarien - Linq to Entities  
Frank Dzaebel, erstellt am: 10.5.2008, zuletzt geändert:  10.05.2008
Kategorie: LINQ to Entities, .NET-Version: 3.5 SP1 Beta1, [Download]

In verteilten Szenarien ist ein Update eines Entities (ADO.NET Entity Framework) nicht komplett trivial. Es gibt zwei Haupt-Techniken: 
Technik 1: Übergabe eines geklonten Original-Objektes.
Technik 2: Das Original innerhalb der Update-Methode über einen (zusätzlichen) RoundTrip vom Server holen. 
                   Siehe dazu: [How to: Apply Changes Made to a Detached Object]

using System;
using System.Linq;
using System.Windows.Forms;
using System.ComponentModel;
using System.Text;
using FrankModel;
using System.Collections;
using System.Reflection;
using System.Data;

namespace EntityFirst
{
  /// <summary>Client (in diesem Fall) ohne ObjectContext.</summary>
  public partial class Client : Form
  {
    public Client()
    {
      InitializeComponent();
    }

    private void Client_Load(object sender, EventArgs e)
    {
      Person neue = Person.CreatePerson(1);
      Person erste = Server.GetFirstPerson();
      ObjectDumper.Write(erste);
      ObjectDumper.Write(neue);

      Person geänderte = erste.Clone();
      geänderte.Alter = 13; 

      Person ersteOriginal = erste.Clone();
      Server.UpdatePerson(geänderte, erste);

      erste = Server.GetFirstPerson();
      ObjectDumper.Write(erste);
    }
  }

  /// <summary>Funktionalität simuliert Server bei verteilter Anwendung.</summary>
  class Server
  {
    /// <summary>Gibt die erste Person des ObjectContext'es zurück und detached sie von ihrem Kontext.</summary>
    public static Person GetFirstPerson()
    {
      using (FrankEntities fe = new FrankEntities())
      {
        var query = from p in fe.Person select p;
        Person first = query.First();
        fe.Detach(first); // p von ObjectContext 'fe' lösen.
        return first;
      }
    }

    /// <summary>Führt ein Update auf dem Server aus</summary>
    public static void UpdatePerson(Person geändert, Person original)
    {
      using (FrankEntities fe = new FrankEntities())
      {
        fe.Attach(original);
        fe.ApplyPropertyChanges(
          original.EntityKey.EntitySetName, geändert);
        fe.SaveChanges();
      }
    }
  }

  public static class Erweiterungen
  {
    /// <summary>Gibt das kopierte Objekt von 'person' zurück. Es werden nur öffentliche Properties kopiert.</summary>
    public static Person Clone(this Person person)
    {
      Person newPerson = new Person();
      PropertyInfo[] props = typeof(Person).
        GetProperties(BindingFlags.Public | BindingFlags.Instance);
      foreach (PropertyInfo pi in props)
        if (pi.Name != "EntityState" && pi.Name != "EntityKey")
          pi.SetValue(newPerson, pi.GetValue(person, null), null);
      return newPerson;
    }
  }
}