Есть ли возможность заставить Entity Framework возвращать пустые строки в нуль? - PullRequest
7 голосов
/ 13 июля 2009

Я использую объектный контекст ADO.NET Entity-Framework для доступа к моему хранилищу данных.

Я хочу, чтобы значения if устанавливались с пустыми строками, они должны автоматически становиться нулевыми.

Ответы [ 8 ]

7 голосов
/ 22 февраля 2011

Если вы используете Entity Framework 4, вы можете использовать шаблоны T4 для достижения этой цели. Просто поместите это в метод получения каждого свойства строки в вашем файле шаблона .tt, и он заменит пустые строки пустыми и автоматически обрезает строки. Не нужно использовать отражение.

<#+ if (primitiveProperty.TypeUsage.ToString().Split('.').Last() == "String") { #>
   if (value == "") value = null;
   else value = value.Trim();
<#+ } #>
6 голосов
/ 13 июля 2009

Я действительно нашел лучший способ для этого, он на самом деле встроен в систему, плюс он использует внутренние порядковые метаданные сущностей, которые загружаются в любом случае (я не проверял разницу в производительности, но это должно быть ад намного быстрее, чем отражение):

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
}
2 голосов
/ 06 августа 2011

Я только что адаптировал приведенный выше код к новому выпуску 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();
1 голос
/ 07 октября 2017

Вот решение для Entity Framework Core (протестировано в V2). Мне пришлось пробиться через API из-за ограниченной документации, так что могут быть другие способы сделать то же самое. Обратите внимание, что исходные объекты модифицируются с помощью этого метода.

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);
}
1 голос
/ 13 июля 2009

Не то, чтобы я знал.

Вы могли бы написать класс, унаследованный от ObjectContext, и переопределить SaveChanges(), чтобы сделать это, и использовать его вместо ObjectContext в вашем x.objectlayer.cs / x.designer.cs

0 голосов
/ 12 марта 2017

Я использовал решение Шимми и был доволен, пока не обнаружил, что строки в моих сложных типах пропускаются. Другими словами, мне нужен был способ обнулить пустые строки, содержащие только пробелы, не только в моем базовом объекте / записи, но и в любых его непримитивных свойствах объекта, а также их и их свойствах ...

Ниже приводится моя рекурсивная адаптация. Я не могу говорить о его элегантности или качестве производства, потому что он не был жив очень долго, но он, кажется, работает для меня до сих пор и может, по крайней мере, послужить отправной точкой для кого-то еще.

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);
    }
}
0 голосов
/ 19 декабря 2013

Просто для полноты, здесь принятый ответ записан как частичный класс, а не как унаследованный. Обратите внимание, что эта версия также обрезает строки.

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

Я также показал требуемый usings, потому что мне неприятно, когда я копирую и вставляю код, а IDE выдает некоторые ошибки о типе или пространстве имен, которые не найдены.

0 голосов
/ 23 апреля 2012

Вместо того, чтобы усложнять ситуацию, переопределяя ObjectContext, я использую методы расширения строк для преобразования значений для хранения базы данных

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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...