【问题标题】:How to save null strings as string.empty when saving changes?保存更改时如何将空字符串保存为 string.empty?
【发布时间】:2016-08-23 22:53:41
【问题描述】:

假设我有一个这样的课程(为简洁起见省略了细节):

public class Address
{
    public Address()
    {
        PostalCode = "";
    }
    public string PostalCode { get; set; } 
}

在映射中,邮政编码为必填项:

public AddressMap()
{
    this.Property(t => t.PostalCode)
        .HasColumnName("PostalCode")
        .IsRequired()
        .HasMaxLength(50);
}

在数据库中定义如下:

CREATE TABLE [dbo].[Address] (
  [PostalCode]   VARCHAR (50)   NOT NULL   DEFAULT ((''))
);

它在代码中初始化为PostalCode的空值:

string pc = null;
var address = New Address()
{ 
    PostalCode = pc 
};

当我将该地址添加到 dbContext 并保存更改时,我得到一个 DbEntityValidationException,因为我试图为 NOT NULL 列保存一个空值。

有没有办法让实体框架或数据库不尝试将.IsRequired 字符串列保存为null,而是将其保存为空字符串?

【问题讨论】:

    标签: c# sql-server entity-framework


    【解决方案1】:

    一种选择是更改属性的get 访问器以删除空值:

    public class Address
    {
        private string _postalCode;
    
        public Address()
        {
            PostalCode = "";
        }
    
        public string PostalCode 
        { 
            get
            {
                //This will never return a null
                return _postalCode ?? "";
            }
            set
            {
                _postalCode = value;
            } 
        }
    }
    

    【讨论】:

    • 更改设置器会起作用,但我想知道是否有解决方案可以在上下文或某种设置上自动执行此操作。例如:设置 { _postalCode = value ?? ""; }
    • 我能想到的唯一其他方法是在保存更改并更改那里的值之前遍历上下文中的实体。但这确实是很多工作。
    • 同意,我想这会很贵而且很慢。
    • 当然,这完全取决于您的用例,但这个答案是最简单、最快捷的方法。它还将您的逻辑保留在实体内部。
    【解决方案2】:

    您始终可以遍历类的不同部分并使用 System.Reflection 执行 nullCheck。下面是一些将泛型类列表传输到 datatable 和 datatableRow 的示例。您可以使用与 GetProperties 相同的想法来执行 null 检查以及将您的类自动转换为 SQL 插入、CSV 数据、XML 或任何您需要的东西。

    public static DataTable create_DataTable_From_Generic_Class(Type t)
        {
            DataTable d = new DataTable();
            FieldInfo[] fI = t.GetFields();
            for(int i = 0; i < fI.Length; i++)
            {
                DataColumn dC = new DataColumn(fI[i].Name, fI[i].FieldType);
                d.Columns.Add(dC);
            }
            return d;
        }
        public static object[] Create_Datatable_Row_From_Generic_Class(Type t, object instance,DataTable dt)
        {
    
            FieldInfo[] f = t.GetFields();
            object[] ret = new object[f.Length];
            for (int i = 0; i < dt.Columns.Count; i++)
            {
                ret[i] = t.GetField(dt.Columns[i].ColumnName).GetValue(instance);
                if (ret[i] == null)
                {
                    ret[i] = "null";
                }
            }
            return ret;
    
        }
    

    【讨论】:

    • 嗨@Shannon - 我可以重写 SaveChanges() 方法来循环添加/更改实体的属性,并使用反射,但我担心这将是一项缓慢而昂贵的任务 - 并且会对我的应用程序性能产生了相当大的影响。
    • Idk - 我经常在 1400 万到 12 亿条记录上使用它,它似乎工作正常。如果您不介意数据按行排列的顺序,则可以使用它。
    【解决方案3】:

    由于某种原因,answer 对我不起作用。很可能是因为一些EF underlying setting。 但是,在[Required] 上添加AllowEmptyStrings = true,即

    [Required(AllowEmptyStrings = true)]

    解决了问题。

    附:我在字符串属性上有[Required],这与提出的问题相比有细微差别。

    【讨论】:

      【解决方案4】:

      为什么要将String初始化为null?如果你使用可能是:

      string pc = String.Empty;
      
      var address = New Address() {    PostalCode = pc  };
      

      如果您想确保永远不会为空,您可以使用@DavidG 的解决方案,但如果您想检查何时为空,您可能只需要初始化为 String.Empty

      【讨论】:

      • 嗨@amalbala - 这只是一个简化的例子。假设我为邮政编码分配了一个从 3rd 方服务返回的字符串。该字符串有时可能为空,可以说我的代码库中有 2000 个地方都有这样的问题。
      【解决方案5】:

      也许在调用 SaveChanges() 之前在上下文类中设置 Configuration.ValidateOnSaveEnabled = false 会起作用。

      context.Configuration.ValidateOnSaveEnabled = false;
      context.SaveChanges();
      

      Entity Framework/MVC3: temporarily disable validation

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-26
        • 1970-01-01
        • 2019-02-16
        相关资源
        最近更新 更多