2009-07-13 7 views
7

Estoy usando un ObjectContext Entity-Framework de ADO.NET para acceder a mi almacén de datos.¿Existe alguna opción para hacer que Entity Framework revierte las cadenas vacías a nulo?

Quiero que los valores if se establezcan con cadenas vacías, que se vuelvan nulos automáticamente.

+1

de otro foro me dieron esta respuesta http://msdn.microsoft.com/en-us/library/vstudio/ms366709(v=vs.100).aspx (ConvertEmptyStringToNull propiedad) – Naomi

+0

Hola Naomi, me Me alegra que lo hayas encontrado, ¿por qué no hacer una respuesta tuya? – Shimmy

Respuesta

5

De hecho, encontré una mejor manera de esto, en realidad está construido en el sistema, además usa los metadatos ordinales internos de las entidades que se cargan de todos modos (no he probado la diferencia de rendimiento, pero esto debería ser mucho más rápido que la reflexión):

private const string StringType = "String"; 
private const EntityState SavingState = EntityState.Added | EntityState.Modified; 
public override int SaveChanges() 
{ 
    //when using on ObjectContext replace 'objectContext' with 'this', 
    //and override SaveChanges(SaveOptions options) instead: 

    var objectContext = ((IObjectContextAdapter)this).ObjectContext; 
    var savingEntries = objectContext.ObjectStateManager 
    .GetObjectStateEntries(SavingState); 

    foreach (var entry in savingEntries) 
    { 
    var curValues = entry.CurrentValues; 
    var fieldMetadata = curValues.DataRecordInfo.FieldMetadata; 
    var stringFields = fieldMetadata 
     .Where(f => f.FieldType.TypeUsage.EdmType.Name == StringType); 
    foreach (var stringField in stringFields) 
    { 
     var ordinal = stringField.Ordinal; 
     var curValue = curValues[ordinal] as string; 
     if (curValue != null && curValue.All(char.IsWhiteSpace)) 
     curValues.SetValue(ordinal, null); 
    } 
    } 
    return base.SaveChanges(); //SaveChanges(options) on ObjectContext 
} 
1

No es que yo sepa.

Usted podría escribir una clase que hereda de ObjectContext y anular SaveChanges() de hacer eso y el uso que en lugar de ObjectContext en sus x.objectlayer.cs/x.designer.cs

+0

oops, mientras escribo esto, lo publicaste ...lol gracias, voté – Shimmy

7

Si usa Entity Framework 4, puede usar plantillas T4 para acco lish esto. Simplemente coloque esto en el captador de cada propiedad de cadena en su archivo de plantilla .tt, y reemplazará las cadenas vacías con nulo y automáticamente recortar cadenas. No es necesario usar la reflexión.

<#+ if (primitiveProperty.TypeUsage.ToString().Split('.').Last() == "String") { #> 
    if (value == "") value = null; 
    else value = value.Trim(); 
<#+ } #> 
+0

Estamos utilizando el generador de POCO inverso y realmente necesito lo contrario (convertir cadenas vacías en vacías). ¿Sabes si tu sugerencia es válida para este escenario? – Naomi

2

Acabo de adaptar el código anterior a la nueva versión de Entity Framework 4.1 (DbContext).

public override int SaveChanges() 
    { 
     var objContext = ((IObjectContextAdapter)this).ObjectContext; 
     var entries = objContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified).Select(
       entry => entry.Entity); 
     foreach (var entity in entries) 
     { 
      string str = typeof(string).Name; 
      var properties = from p in entity.GetType().GetProperties() 
          where p.PropertyType.Name == str 
          select p; 

      foreach (var item in properties) 
      { 
       string value = (string)item.GetValue(entity, null); 
       if (value != null && value.Trim().Length == 0) 
       { 

        item.SetValue(entity, null, null); 

       } 
      } 
     } 
     return base.SaveChanges(); 
0

En lugar de complicar las cosas reemplazando el ObjectContext utilizo métodos de extensión de cadena para convertir los valores para el almacenamiento de base de datos

public static class StringExtensions 
{ 
    public static string EmptyStringToNull(this string s) 
    { 
     return string.IsNullOrWhiteSpace(s) ? null : s; 
    } 

    public static object EmptyStringToDBNull(this string s) 
    { 
     if (string.IsNullOrWhiteSpace(s)) 
      return DBNull.Value; 
     else 
      return s; 
    } 
} 
+0

¿Estás seguro de que esto funcionará en las consultas DB? Yo creo que no. – Shimmy

0

simplemente para la corrección, aquí está la respuesta aceptada por escrito como una clase parcial en lugar de heredada . Tenga en cuenta que esta versión también recorta cadenas.

using System.Data; 
using System.Data.Objects; 
using System.Linq; 
public partial class MyObjectContext { 
    private const string StringType = "String"; 
    private const EntityState SavingState = EntityState.Added | EntityState.Modified; 

    public override int SaveChanges(SaveOptions options) { 
     var savingEntries = this.ObjectStateManager.GetObjectStateEntries(SavingState); 

     foreach (var entry in savingEntries) { 
      var curValues = entry.CurrentValues; 
      var fieldMetadata = curValues.DataRecordInfo.FieldMetadata; 
      var stringFields = fieldMetadata.Where(f => f.FieldType.TypeUsage 
                 .EdmType.Name == StringType); 

      foreach (var stringField in stringFields) { 
       var ordinal = stringField.Ordinal; 
       var curValue = curValues[ordinal] as string; 

       if (curValue != null && curValue.All(char.IsWhiteSpace)) { 
        curValues.SetValue(ordinal, null); 
       } 
       else if (curValue != null && curValue != curValue.Trim()) { 
        curValues.SetValue(ordinal, curValue.Trim()); 
       } 
      } 
     } 
     return base.SaveChanges(options); 
    } 
} 

También he mostrado la necesaria usings porque me resulta frustrante cuando Copy'n'Paste código y el IDE vomita sobre algunos errores de tipo o espacio que no se encuentra.

0

Usé Shimmy's solution y me complació hasta que descubrí que las cadenas en mis tipos complejos se estaban perdiendo. En otras palabras, necesitaba una forma de anular las cadenas de espacios en blanco anulables no solo en mi objeto/registro central, sino en cualquiera de sus propiedades de objetos no primitivos, y de ellos, y de ellos ...

El siguiente es mi adaptación recursiva. No puedo hablar de su elegancia o calidad de producción porque no ha sido en vivo por mucho tiempo, pero parece estar funcionando para mí hasta ahora y al menos puede servir como punto de partida para otra persona.

using System.Data.Entity; 
using System.Data.Entity.Core.Metadata.Edm; 
using System.Data.Entity.Core.Objects; 
using System.Data.Entity.Infrastructure; 
using System.Linq; 

public class MyDataContext : DbContext 
{ 
    public override int SaveChanges() 
    { 
     ObjectStateEntry[] savingObjectStateEntries = ((IObjectContextAdapter)this) 
      .ObjectContext.ObjectStateManager 
      .GetObjectStateEntries(EntityState.Added | EntityState.Modified).ToArray(); 
     foreach (ObjectStateEntry savingObjectStateEntry in savingObjectStateEntries) 
      SetEmptyStringsToNull(savingObjectStateEntry.CurrentValues); 

     return base.SaveChanges(); 
    } 

    private static void SetEmptyStringsToNull(CurrentValueRecord currentValueRecord) 
    { 
     if (currentValueRecord != null) 
      for (int i = 0; i < currentValueRecord.FieldCount; i++) 
       if (currentValueRecord[i] is CurrentValueRecord) 
        SetEmptyStringsToNull(currentValueRecord[i] as CurrentValueRecord); 
       else if ((currentValueRecord[i] is string) 
        && (currentValueRecord.DataRecordInfo.FieldMetadata[i].FieldType as EdmProperty).Nullable 
        && string.IsNullOrWhiteSpace(currentValueRecord[i] as string)) 
        currentValueRecord.SetValue(i, null); 
    } 
} 
1

Aquí hay una solución para Entity Framework Core (probado en V2). Tuve que abrirme camino a través de la API debido a la documentación limitada, por lo que podría haber otras formas de lograr lo mismo. Tenga en cuenta que los objetos originales se modifican con este método.

public override int SaveChanges() 
{ 
    ConvertWhitespaceToNulls(); 
    return base.SaveChanges(); 
} 


private void ConvertWhitespaceToNulls() 
{ 
    var entityEntries = this.ChangeTracker 
     .Entries() 
     .Where(x => x.State == EntityState.Modified || x.State == EntityState.Added && x.Entity != null); 

    foreach (var e in entityEntries) 
     foreach (var currentValue in e.CurrentValues.Properties.Where(p => p.ClrType == typeof(string) && p.IsNullable)) 
      if (string.IsNullOrWhiteSpace((string) currentValue.FieldInfo.GetValue(e.Entity))) 
       currentValue.FieldInfo.SetValue(e.Entity, null); 
} 
Cuestiones relacionadas