2009-07-13 4 views
7

J'utilise un Entity-Framework ObjectContext ADO.NET pour accéder à mon magasin de données. Je veux que les valeurs if soient définies avec des chaînes vides, elles devraient automatiquement devenir nulles.Existe-t-il une option permettant à Entity Framework de rétablir les chaînes vides à null?

+1

D'un autre forum, je suis arrivé cette réponse http://msdn.microsoft.com/en-us/library/vstudio/ms366709(v=vs.100).aspx (propriété ConvertEmptyStringToNull) – Naomi

+0

Salut Naomi, je Je suis content que vous l'ayez trouvé, pourquoi ne pas répondre vous-même? – Shimmy

Répondre

5

j'ai trouvé une meilleure façon de En fait, il est construit dans le système, et utilise les métadonnées ordinales internes des entités qui sont chargées (je n'ai pas testé la différence de performance, mais cela devrait être bien plus rapide que la réflexion):

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

Pas que je sache.

Vous pourriez peut-être écrire une classe qui a hérité de ObjectContext et passer outre SaveChanges() de le faire et utiliser à la place de ObjectContext dans votre x.objectlayer.cs/x.designer.cs

+0

oups, alors que j'écris ceci, vous l'avez posté ...lol merci, j'ai voté – Shimmy

7

Si vous utilisez Entity Framework 4, vous pouvez utiliser des modèles T4 pour accompagner ça. Placez-le simplement dans le getter de chaque propriété de chaîne dans votre fichier de modèle .tt, et il remplacera les chaînes vides par des chaînes nulles et automatiquement ajustées. Pas besoin d'utiliser la réflexion.

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

Nous utilisons Reverse POCO Generator et j'ai en fait besoin de l'inverse (convertir les chaînes null à vide). Savez-vous si votre suggestion est valable pour ce scénario? – Naomi

2

Je viens d'adapter le code ci-dessus à la nouvelle version d'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

Plutôt que de compliquer les choses en redéfinissant la ObjectContext J'utilise des méthodes d'extension de chaîne pour convertir les valeurs pour le stockage de base de données

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

Etes-vous sûr que cela va marcher sur les requêtes DB? Je crois que ce ne sera pas le cas. – Shimmy

0

Juste pour être complet, voici la réponse acceptée par écrit en tant que classe partielle au lieu de héritée . Notez que cette version coupe également les chaînes.

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); 
    } 
} 

J'ai aussi montré la nécessaire usings parce que je trouve frustrant quand je Copy'n'Paste code et l'IDE vomit des erreurs sur le type ou espace de noms introuvable.

0

J'ai utilisé Shimmy's solution et j'étais heureux jusqu'à ce que je découvre que les chaînes de mes types complexes étaient manquées. En d'autres termes, j'avais besoin d'un moyen d'annuler les chaînes d'espaces vides valables dans non seulement mon objet/enregistrement principal, mais toutes ses propriétés d'objet non-primitives, et leurs et leurs ...

adaptation récursive. Je ne peux pas parler de son élégance ou de la qualité de sa production parce qu'elle n'a pas été très vivante depuis longtemps, mais elle semble fonctionner pour moi jusqu'à présent et peut au moins servir de point de départ pour quelqu'un d'autre.

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

Voici une solution pour Entity Framework Core (testé en V2). J'ai dû me frayer un chemin à travers l'API en raison d'une documentation limitée, donc il pourrait y avoir d'autres façons d'accomplir la même chose. Notez que les objets d'origine sont modifiés à l'aide de cette méthode.

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); 
} 
Questions connexes