【问题标题】:CsvHelper Ignore Complex TypesCsvHelper 忽略复杂类型
【发布时间】:2020-11-11 19:25:48
【问题描述】:

我正在尝试将测试数据从 CSV 文件加载到可以加载到 In-Memory EF Core DB 上下文中的记录中。

我有一个简化的实体,如下所示:

public class Project
{
   public int { get; set; }
   public Owner? Owner { get; set; } = null;
}

类地图:

public class ProjectsClassMap : CsvHelper.Configuration.ClassMap<Projects>
{
     public ProjectsClassMap()
     {
        AutoMap(CultureInfo.CurrentCulture);
        Map(m => m.Owner).Ignore();

    }
}

然后是这样加载数据的函数:

private void LoadTestData<T>(string fileName, InMemoryEFCoreDbContext db, Type? classMap = null)
            where T : class
        {
            var data = GetTestData(fileName);
            var readerConfig = new CsvConfiguration(CultureInfo.CurrentCulture) {
                Delimiter = ",",
                PrepareHeaderForMatch = (r, c) => r.Replace(" ", string.Empty).ToLower(),
                MissingFieldFound = (string[] values, int index, ReadingContext context) => { },
                ReadingExceptionOccurred = (ex) => false,
                HeaderValidated = (isValid, headerNames, headerNameIndex, context) => { },
                HasHeaderRecord = true,
                UseNewObjectForNullReferenceMembers = true,
            };
            if(classMap != null)
            {
                readerConfig.RegisterClassMap(classMap);
                readerConfig.IgnoreReferences = true;
            }
            
            using (var sReader = new StringReader(data))
            using (var csvReader = new CsvHelper.CsvReader(sReader, readerConfig))
            {
                var records = csvReader.GetRecords<T>().ToList();
                db.Set<T>().AddRange(records);
                db.SaveChanges();
            }
        }

问题是所有者设置为新值而不是默认值 null,这会在尝试保存到 DbContext 时导致验证错误。如何将复杂引用类型保留为 null 而不是 new?

【问题讨论】:

    标签: csvhelper


    【解决方案1】:

    试试这个

    public class ProjectsClassMap : CsvHelper.Configuration.ClassMap<Project>
    {
        public ProjectsClassMap()
        {
            var config = new CsvConfiguration(CultureInfo.CurrentCulture)
            {
                IgnoreReferences = true
            };
            AutoMap(config);
        }
    }
    

    @JoshClose 更新

    这里的问题是 AutoMap 将设置树下的所有属性,而忽略该属性不会删除 Owner 上的所有属性。

    在没有ProjectsClassMapAutoMap 的情况下使用[Ignore] 属性将正确设置它。

    public class Project
    {
       public int { get; set; }
       [Ignore]
       public Owner? Owner { get; set; } = null;
    }
    

    或者,如果您需要使用类映射,则必须手动删除引用。

    public class ProjectsClassMap : CsvHelper.Configuration.ClassMap<Project>
    {
        public ProjectsClassMap()
        {   
            AutoMap(CultureInfo.CurrentCulture);
            ReferenceMaps.Remove(ReferenceMaps.Find<Project>(m => m.Owner));
        }
    }
    

    【讨论】:

    • 我也试过了,但是没用。我可以让它工作的唯一方法是使引用类型不可为空。像 public Owner Owner { get;放; } 而不是公共所有者?所有者{得到;放; }
    • C# 8 的一个特性是使可空性更加明确并且更容易被编译器捕获。通过使用所有者?您会告诉编译器该值可能为 null
    • 这里的问题是AutoMap 将设置树下的所有属性并且忽略该属性不会删除Owner 上的所有属性。如果您的ClassMap 如此简单并且您可以控制该类,请将[Ignore] 属性添加到Owner 属性,AutoMap 将正确设置它。如果您没有控制权并且需要使用类映射,则必须手动删除引用 ReferenceMaps.Remove(ReferenceMaps.Find&lt;Project&gt;(m =&gt; m.Owner));
    • @JoshClose 我已将您的更新添加到答案中。仅供参考,即使使用public Owner? Owner { get; set; } = null;,第一个答案也对我有用
    • @DavidSpecht 再次感谢您的所有回答!
    猜你喜欢
    • 1970-01-01
    • 2023-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-15
    • 2014-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多