niedziela, 13 stycznia 2013

[SQL|ORM] Entity Framework : Obiekty Entity Framework

Obiekty EF można dostosować do potrzeb aplikacji na bardzo wiele sposobów. W tym poście kilka użytecznych przykładów w tym temacie.

Wykonywanie własnego kodu, podczas wywołania metody SaveChanges

Wystarczy nadpisać metodę SaveChanges z obiektu kontekstu. Stan obiektów dostępny jest w ObjectStateManager.

public override int SaveChanges(SaveOptions options)
        {
            Console.WriteLine("Saving Changes");
            var applicants = this.ObjectStateManager
                                .GetObjectStateEntries(EntityState.Deleted)
                                .Select(e => e.Entity)
                                .OfType<Applicant>().ToList();
            int changes = base.SaveChanges(options);
            Console.WriteLine("\n{0} applicants deleted",
                applicants.Count().ToString());

            foreach (var applicant in applicants)
            {
                File.Delete(applicant.ResumePath);
                Console.WriteLine("\n{0}File deleted at {1}", applicant.Name,
                    applicant.ResumePath);
            }
            return changes;
        }

Reguły walidacyjne dla propercji 

Aby dodać prostą regułę walidacyjną należy na obiekcie encji nadpisać metody zgodne z nazwą property. Metody te generowane są przez EF. Na przykład dla property UserName mamy możliwe OnUserNameChanging oraz OnUserNameChanged. W tych metodach mamy dostęp do encji, więc możemy modyfikować jej pola. Metody takie wołane są nie tylko przy zmianie wartości property ale także przy materializowaniu encji podczas jej pobierania z bazy danych.

public partial class User
{
    partial void OnUserNameChanging(string value)
    {
        if (value.Length > 5)
            Console.WriteLine("{0}'s UserName changing to {1}, OK!",
                this.FullName, value);
        else
            Console.WriteLine("{0}'s UserName changing to {1}, TooShort!",
                this.FullName, value);
    }

    partial void OnUserNameChanged()
    {
        this.IsActive = this.UserName.Length > 5;
    }
}

Logowanie połączeń do bazy danych

Aby logować połączenia możemy zasubskrybować się na zdarzenie StateChange z property Connection dostępnej w obiekcie kontekstu.

this.Connection.StateChange += (s, e) =>
    {
        var conn = ((EntityConnection) s).StoreConnection;
        Console.WriteLine("{0}: Database: {1}, State: {2} was {3}",
                            DateTime.Now.ToShortTimeString(), conn.Database,
                            e.CurrentState, e.OriginalState);
    };

Walidacja przy SaveChanges

Czasami do walidacji potrzebujemy dwie wartości encji: nową i poprzednią (np. procentowy przyrost płac). Odpowiednim miejscem, w którym mamy dostęp do obu wartości jest zdarzenie SavingChanges.

public partial class EntityFrameworkRecipesEntities3
{
    partial void OnContextCreated()
    {
     this.SavingChanges += new EventHandler(EntityFrameworkRecipesEntities3_SavingChanges);
    }

    void EntityFrameworkRecipesEntities3_SavingChanges(object sender, EventArgs e)
    {
     var entries = this.ObjectStateManager
         .GetObjectStateEntries(EntityState.Modified)
         .Where(entry => entry.Entity is Employee);
     foreach(var entry in entries)
     {
      var salaryProp = entry.GetModifiedProperties()
           .FirstOrDefault(p => p == "Salary");
      if(salaryProp != null)
      {
       var originalSalary = Convert.ToDecimal(
            entry.OriginalValues[salaryProp]);
       var currentSalary = Convert.ToDecimal(
            entry.CurrentValues[salaryProp]);
       if(originalSalary != currentSalary)
       {
        if(currentSalary > 1.1M*originalSalary)
        {
         throw new ApplicationException("Can't increase salary more than 10%");
        }
       }
      }

     }
    }
}

Brak komentarzy:

Prześlij komentarz