2010-10-12 13 views
6

Im utilizando EF4 en VS2010, POCO y el primer enfoque del modelo.¿Cómo se actualiza automáticamente la propiedad modificada en una entidad en Entity Framework 4 al guardar?

Mi entidad tiene las siguientes propiedades: Id: Guid, Nombre: String, Creado: DateTime, Modificado: DateTime, Revisión: Int32.

Creo mi entidad, establezco el nombre y lo guardo en la base de datos utilizando el contexto EF4. Esto debería establecer Id en un nuevo Guid (funciona con Identity-SGP), Creado establecido ahora, Modificado a la izquierda como nulo, Revisión a 0. Recupero la entidad, cambio el nombre y lo guardo de nuevo. Esta vez, el valor modificado debe establecerse ahora y la revisión debe ser 1.

¿Cómo puedo lograr esto utilizando EF4 con el diseñador EDMX?

Actualización:

Esto fue lo que terminó usando:

public override int SaveChanges(System.Data.Objects.SaveOptions options) 
{ 
    foreach (ObjectStateEntry entry in ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified).Where(e => e.Entity is EntityBase)) 
    { 
     EntityBase entity = entry.Entity as EntityBase; 
     if (entry.State == EntityState.Added) 
     { 
      entity.Version = new Version() { Major = 1, Minor = 0, Revision = 0 }; 
      entity.Created = DateTime.Now; 
      if (OperationContext.Current != null) entity.CreatedBy = OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name; 
     } 
     else if (entry.State == EntityState.Modified) 
     { 
      entity.Version.Revision++; 
      entity.Modified = DateTime.Now; 
      if (OperationContext.Current != null) entity.ModifiedBy = OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name; 
     } 
    } 

    return base.SaveChanges(options); 
} 

que tampoco funciona ... :(

El problema es que el entry.State todavía no modificada incluso si ejecuto explícitamente el método MarkAsModified(). No lo consigo ...

¿Por qué el seguimiento de cambios no está habilitado de manera predeterminada? Por ejemplo, ¿por qué me gustaría tenerlas y volver a activarlas explícitamente? ¿Y por qué persisten las entidades para db incluso si el estado no está modificado? ¿Y cuál es la diferencia entre EntityState y ObjectState? Por el momento estoy haciendo todos los cambios y actualizaciones en el servidor, pero también usaré un servicio WCF para transferir entidades de un lado a otro más adelante ... ¿Hay alguna diferencia en cómo se tratan los cambios aquí? Si todos los cambios en el servidor, sin importar el cambio de seguimiento activado/desactivado, persisten? Lo que quiero es que nunca se pueda almacenar nada sin actualizar también Modified, Revision, etc. Estas propiedades siempre deben establecerse en el servidor cuando el objeto se recibe y ha cambiado. (No estoy hablando-del lado del servidor SQL aquí, pero el servicio del lado del servidor)

Respuesta

3

Supongamos que su nombre del tipo de entidad es del producto:

partial void OnContextCreated() { 
    this.SavingChanges += Context_SavingChanges; 
} 

void Context_SavingChanges(object sender, EventArgs e) { 

    IEnumerable objectStateEntries = 
      from ose 
      in this.ObjectStateManager.GetObjectStateEntries(EntityState.Added | 
                  EntityState.Modified) 
      where ose.Entity is Product 
      select ose; 

    Product product = objectStateEntries.Single().Entity as Product; 

    product.ModifiedDate = DateTime.Now; 
    product.ComplexProperty.Revision++; 
} 


Si usted está buscando para utilizar el código para poblar común campo como ModifiedDate o ModifiedBy para todas sus entidades, por favor, eche un vistazo a este post:
Entity Framework - Auditing Activity

por cierto, StoreGeneratedPattern y ConcurrencyMode no tiene nada que ver con esto, ellos están allí para cosas completamente diferentes y sin relación.

+0

Gracias Lo intentaré, pero ¿hay alguna forma de hacerlo en el servidor sql en la actualización? –

+0

Por supuesto, puede escribir un "disparador" de base de datos que actualice la tabla al insertar y actualizar. Esta es una solución para hacerlo en el lado del cliente con el marco de la entidad. –

+0

He intentado con su método, pero estoy teniendo problemas para establecer una propiedad int dentro de una propiedad ComplexType en la entidad actualizada. Tengo una versión de ComplexType con tres entradas y solo quiero actualizar el último valor. Establecer una nueva versión falla completamente con una excepción que me dice que tengo que implementar IExtendedDataRecord. ¿Es eso realmente necesario? –

0

Soy parcial a una solución basada en el código del lado del cliente, personalmente. Dado que está utilizando POCO, probablemente sería más simple hacer que el objeto mismo realice la actualización. Actualizar el acceso de escritura en la propiedad Name para llamar a un método "objectModified" que cambia las propiedades modificadas y revisión.

Si eso es desagradable debido a la diferencia de tiempo entre el momento en que se cambia la propiedad y el tiempo se guarda el objeto, se puede aprovechar la clase parcial en el objeto de sus entidades. Si lo hace, le permitirá reemplazar el método SaveChanges donde se puede tocar sus ENTIDADES en su ObjectSet <T> propiedad en el objeto de las Entidades.Algo como:

public partial class YourEntities 
{ 
    public override int SaveChanges(System.Data.Objects.SaveOptions options) 
    { 
     //update your objects here 
     return base.SaveChanges(options); 
    } 
} 
+0

Pero si actualizo mi SQL desde otro lugar que no use EF4, aún así me gustaría que la columna de Revisión aumente y sería bueno si la columna Modificada también cambiara. Tengo que pensar en esto, puedo usar una solución combinada. ¡Gracias por su respuesta! –

+0

Probé el método que sugirió pero al agregar nuevos objetos no aparecerán en mi contexto. Edades. Está vacío ... ¿alguna idea de por qué? –

+0

Notado que tenía que ejecutar explícitamente entity.StartTracking() para que cambie el estado a modificado. ¿Cómo puedo activarlo por defecto? ¿Y por qué mis cambios se guardan cuando ejecuto SaveChanges() cuando ChangeTracking está DESACTIVADO y estado == sin cambios ??? Weird ... –

0

Podemos utilizar la clase parcial y anular el método SaveChanges para lograr esto.

using System; 
using System.Collections.Generic; 
using System.Data.Entity; 
using System.Data.Entity.Core.Objects; 
using System.Data.Entity.Infrastructure; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Web; 


namespace TestDatamodel 
{ 
    public partial class DiagnosisPrescriptionManagementEntities 
    { 
     public override int SaveChanges() 
     { 
      ObjectContext context = ((IObjectContextAdapter)this).ObjectContext; 

      foreach (ObjectStateEntry entry in 
        (context.ObjectStateManager 
         .GetObjectStateEntries(EntityState.Added | EntityState.Modified))) 
      {      
       if (!entry.IsRelationship) 
       { 
        CurrentValueRecord entryValues = entry.CurrentValues; 
        if (entryValues.GetOrdinal("ModifiedBy") > 0) 
        { 
         HttpContext currentContext = HttpContext.Current; 
         string userId = "nazrul"; 
         DateTime now = DateTime.Now; 

         if (currContext.User.Identity.IsAuthenticated) 
         { 
          if (currentContext .Session["userId"] != null) 
          { 
           userId = (string)currentContext .Session["userId"]; 
          } 
          else 
          {          
           userId = UserAuthentication.GetUserId(currentContext .User.Identity.UserCode); 
          } 
         } 

         if (entry.State == EntityState.Modified) 
         { 
          entryValues.SetString(entryValues.GetOrdinal("ModifiedBy"), userId); 
          entryValues.SetDateTime(entryValues.GetOrdinal("ModifiedDate"), now); 
         } 

         if (entry.State == EntityState.Added) 
         { 
          entryValues.SetString(entryValues.GetOrdinal("CreatedBy"), userId); 
          entryValues.SetDateTime(entryValues.GetOrdinal("CreatedDate"), now); 
         } 
        } 
       } 
      } 

      return base.SaveChanges(); 
     } 
    } 
} 
Cuestiones relacionadas