RSS FeedFeed TwitterTwitter XINGXING
  
Meine Bücher

Verteilte Systeme und Services mit .NET 4.0: Konzepte und Lösungen mit WCF 4.0,
Hanser Fachbuchverlag

Weitere Infos

 

.NET 4 Update,
Microsoft Press

Weitere Infos

 
Weitere Bücher
Meine Artikel

Leichtgewichtige Kommunikation: REST-basierte Services mit dem neuen API aus der ASP.NET-Familie,
windows.developer

Weitere Infos

 

EAI und EDI in der Cloud ,
windows.developer

Weitere Infos

 

Verteilt und doch ein Ganzes: Verteilte Systeme mit AppFabric Applications,
dot.net magazin

Weitere Infos

 

Vorschau auf Neuerungen der kommenden WCF-Version,
dot.net magazin

Weitere Infos

 

Windows Azure Tutorial, Teil 3: Verbindung zwischen Cloud- und lokalen Applikationen,
iX - Magazin für professionelle Informationstechnik

Weitere Infos

 

MVC, die dritte: ASP.NET MVC 3 RC 2,
dot.net magazin

Weitere Infos

 

Leichtgewichtiges O/R-Mapping - Code Only mit Entitiy Framework CTP 5,
dot.net magazin

Weitere Infos

 

Weitere Artikel

Training & Beratung

Gemeinsam mit meinen Kollegen aus dem IT-Visions Netzwerk unterstützte ich durch zielgerichtete Inhouse-Schulungen und Beratung Unternehmen bei der Planung und Umsetzung von großer Software-Systeme.

Mehr lesen

In Kontakt treten

 
Konferenzen

BASTA! on Tour von 4/25/2012 bis 4/27/2012 in Düsseldorf

Meine Talks

Web-Site der Konferenz

 

BASTA! Spring 2012 von 2/27/2012 bis 3/2/2012 in Darmstadt

Meine Talks

Web-Site der Konferenz

 

ADC - Advanced Developers Conference von 10/26/2011 bis 10/27/2011 in Frankental (Deutschland)

Meine Talks

Web-Site der Konferenz

 

Scandev on tour von 10/18/2011 bis 10/18/2011 in Stockholm (Schweden)

Meine Talks

Web-Site der Konferenz

 

BASTA 2011 von 9/26/2011 bis 9/30/2011 in Mainz

Meine Talks

Web-Site der Konferenz

 

Jazoon - International Conference on the modern art of software von 6/21/2011 bis 6/23/2011 in Zürich

Meine Talks

Web-Site der Konferenz

 

Scandinavian Developer Conference 2011 von 4/4/2011 bis 4/5/2011 in Göteborg (Schweden)

Meine Talks

Web-Site der Konferenz

 

SOA-Days von 3/30/2011 bis 3/31/2011 in Bonn

Meine Talks

Web-Site der Konferenz

 
Weitere Konferenzen
von Manfred, 25. August 2011 12:48
Zur Zeit muss man leider zwischen Self Tracking Entities und Code Only entscheiden. Was aber, wenn man Code Only in einer verteilten Umgebung einsetzen möchte? In diesem Fall wäre es wünschenswert, die Vorteile beider Ansätze miteinander zu verbinden. Das nachfolgende Beispiel zeigt, wie dies bewerkstelligt werden kann. Der erste Teil beinhaltet ein paar allgemeine Konstrukte; der zweite Teil zeigt die Anwendung dieser Konstrukte anhand eines einfachen Beispiels.
// --- Wiederverwendbarer Teil --------------

public enum DetachedEntityState
{
    New, Updated, Deleted, Unchanged
}

public interface IEntity
{
    DetachedEntityState State { get; set; }
}

public static class StateTrackingHelper
{

    public static void ApplyStates<T>(this ICollection<T> entities, DbContext ctx) where T : class, IEntity 
    {
        foreach (var e in entities.ToArray())
        {
            ApplyState(e, ctx);
        }
    }

    public static void ApplyState<T>(this T entity, DbContext ctx) where T : class, IEntity
    {
        switch (entity.State)
        {
            case DetachedEntityState.New:
                ctx.Entry<T>(entity).State = System.Data.EntityState.Added;
                break;
            case DetachedEntityState.Updated:
                ctx.Entry<T>(entity).State = System.Data.EntityState.Modified;
                break;
            case DetachedEntityState.Deleted:
                ctx.Entry<T>(entity).State = System.Data.EntityState.Deleted;
                break;
        }
    }

    public static ICollection<T> ResetStates<T>(this ICollection<T> entities) where T : class, IEntity
    {
        var deleted = new List<T>();

        foreach (var e in entities)
        {
            if (e.State != DetachedEntityState.Deleted)
            {
                ResetState(e);
            }
        }

        return entities;
    }

    public static void ResetState<T>(this T entity) where T : class, IEntity
    {
        entity.State = DetachedEntityState.Unchanged;
    }
        
}

// --- Anwendung --------------

public class Region: IEntity
{
    public Region()
    {
        Hotels = new List<Hotel>();
        Top10Hotels = new List<Hotel>();
    }

    private int _RegionId;
    public int RegionId
    {
        get
        {
            return _RegionId;
        }
        set
        {
            if (_RegionId != value) {
                _RegionId = value;
                this.State = DetachedEntityState.Updated; 
            }
        }
    }
    private string _Bezeichnung;
    public string Bezeichnung
    {
        get
        {
            return _Bezeichnung;
        }
        set
        {
            if (_Bezeichnung != value) {
                _Bezeichnung = value;
                this.State = DetachedEntityState.Updated; 
            }
        }
    }

    private ICollection<Hotel> _Hotels;

    public virtual ICollection<Hotel> Hotels
    {
        get
        {
            return _Hotels;
        }
        set
        {
            if (_Hotels != value) {
                _Hotels = value;
                this.State = DetachedEntityState.Updated; 
            }

        }
    }
    private ICollection<Hotel> _Top10Hotels;
    public virtual ICollection<Hotel> Top10Hotels
    {
        get
        {
            return _Top10Hotels;
        }
        set
        {
            if (_Top10Hotels != value) {
                _Top10Hotels = value;
                this.State = DetachedEntityState.Updated; 
            }

                 
        }
    }

    private DetachedEntityState _State;
    [NotMapped]
    public DetachedEntityState State
    {
        get
        {
            return _State;
        }
        set
        {
            _State = value;
        }
    }
}

public class Hotel : IEntity
{
    private int _HotelId;
    public int HotelId
    {
        get
        {
            return _HotelId;
        }
        set
        {

            if (_HotelId != value) {
                _HotelId = value;
                this.State = DetachedEntityState.Updated; 
            }

            
        }
    }
    private string _Bezeichnung;
    public string Bezeichnung
    {
        get
        {
            return _Bezeichnung;
        }
        set
        {
            if (_Bezeichnung != value) {
                _Bezeichnung = value;
                this.State = DetachedEntityState.Updated; 
            }
                
        }
    }
    private int _Sterne;
    public int Sterne
    {
        get
        {
            return _Sterne;
        }
        set
        {

            if (_Sterne != value) {
                _Sterne = value;
                this.State = DetachedEntityState.Updated; 
            }
        }
    }

    private int _RegionId;
    public int RegionId
    {
        get
        {
            return _RegionId;
        }
        set
        {
            if (_RegionId != value) {
                _RegionId = value;
                this.State = DetachedEntityState.Updated; 
            }
        }
    }

    private Region _Region;
    [ForeignKey("RegionId"), InverseProperty("Hotels")]
    public virtual Region Region
    {
        get
        {
            return _Region;
        }
        set
        {
            if (_Region != value) {
                _Region = value;
                this.State = DetachedEntityState.Updated; 
            }
        }
    }

    private DetachedEntityState _State;
    [NotMapped]
    public DetachedEntityState State
    {
        get
        {
            return _State;
        }
        set
        {
            _State = value;
        }
    }
        
}

public class WellnessHotel : Hotel
{
    private int _AnzahlSaunen;
    public int AnzahlSaunen
    {
        get
        {
            return _AnzahlSaunen;
        }
        set
        {
            if (_AnzahlSaunen != value) {
                _AnzahlSaunen = value;
                this.State = DetachedEntityState.Updated; 
            }
                
        }
    }
    private int _AnzahlThermalBecken;
    public int AnzahlThermalBecken
    {
        get
        {
            return _AnzahlThermalBecken;
        }
        set
        {
            if (_AnzahlThermalBecken != value) {
                _AnzahlThermalBecken = value;
                this.State = DetachedEntityState.Updated; 
            }
        }
    }
}

public class HotelDbContext : DbContext
{
    public HotelDbContext(): base("CodeOnlyHotelDb") { } 

    public DbSet<Hotel> Hotels { get; set; }
    public DbSet<Region> Regionen { get; set; }
}

public class RegionDAO
{

    public List<Region> FindAll()
    {
        using (var ctx = new HotelDbContext())
        {
            var result = ctx.Regionen.Include("Hotels").ToList();
            result.ResetStates();
            return result;
        }

    }

    public void UpdateRegion(Region r)
    {
        using (var ctx = new HotelDbContext())
        {
            ctx.Regionen.Attach(r);

            r.ApplyState(ctx);
            r.Hotels.ApplyStates(ctx);
                
            ctx.SaveChanges();

            r.ResetState();
            r.Hotels.ResetStates();
        }
    }

    public void SaveRegion(Region r1)
    {
        using (var ctx = new HotelDbContext())
        {
            ctx.Regionen.Add(r1);
            ctx.SaveChanges();
        }
    }



}

class Program
{
    static void Main(string[] args)
    {
        Database.SetInitializer(new DropCreateDatabaseAlways<HotelDbContext>());

        CreateSaveModifySaveDemo();
        LoadShowModifySaveDemo();
        LoadShowModifySaveDemo();

        Console.WriteLine("fertig!");
        Console.ReadLine();

    }

    private static void CreateSaveModifySaveDemo()
    {
        var dao = new RegionDAO();

        Region r1 = new Region { Bezeichnung = "Graz" };
        Hotel h1 = new Hotel { Bezeichnung = "Hotel zur Post", Sterne = 2 };

        WellnessHotel h2 = new WellnessHotel
        {
            Bezeichnung = "Hotel zur Wellness",
            Sterne = 4,
            AnzahlSaunen = 3,
            AnzahlThermalBecken = 4
        };

        r1.Hotels.Add(h1);
        r1.Hotels.Add(h2);
        r1.Top10Hotels.Add(h2);

        dao.SaveRegion(r1);

        h2.Sterne++;
        r1.Bezeichnung += "!"; // kleine Änderung

        dao.UpdateRegion(r1);
    }

    private static void LoadShowModifySaveDemo()
    {
        var dao = new RegionDAO();

        var regionen = dao.FindAll();
        foreach (var r in regionen)
        {
            Console.WriteLine(r.Bezeichnung);
            r.Bezeichnung += "$"; // kleine Änderung
            int i = 0;
            foreach (var h in r.Hotels)
            {
                Console.WriteLine("    " + h.Bezeichnung + ", Sterne: " + h.Sterne);
                if (i++ % 2 == 0)
                {
                    h.Bezeichnung += "$"; // kleine Änderung
                }
                else
                {
                    h.State = DetachedEntityState.Deleted;
                }
            }
            Console.WriteLine();
            dao.UpdateRegion(r);
        }
            
    }

}
Hinweis: Nach dem Laden der Daten muss einmal Reset, wie oben gezeigt, aufgerufen werden, da EF die Entitäten im Zuge des Materialisierens verändert bzw. weil der Standardwert von DetachedEntityState der Wert New ist.

Kategorien: .Net 4 | Entity Framework