[使用CSVHelper将CSV映射到嵌套的POCO元素

问题描述 投票:0回答:1

我有一个旧的旧数据库,该数据库已转换为CSV,我试图在其中使用CSVHelper解析和分解数据,以便播种新数据库(使用实体框架)。

例如,我有以下CSV标头;

Rec,ID,FirstName,Lastname,Email,BusinessPhone,Company,JobTitle,HomePhone,MobilePhone,FaxNumber,Address,City,State,PostalCode,Country,WebPage,Term,Website,CompanyReg,YearEstablished,AgreementNumber,ExpiryDate

(为简洁起见,这是一种减少)

在新系统下,我们具有以下POCO地图(为简便起见,再次简化;]

public class Company 
{
    public string Name { get; set; }
    public string Website { get; set; }

    public int AddressId { get; set; }
    public Address Address { get; set; }

    public IList<Contact> Contacts { get; set; }
}

public class Address 
{
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string Address3 { get; set; }
    public string Town { get; set; }
    public string Region { get; set; }
    public string PostCode { get; set; }
    public string Country { get; set; }
    public bool IsPrimaryAddress { get; set; }

}

public class Contact 
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string HomeTelephone { get; set; }
    public string BusinessTelephone { get; set; }
    public string Mobile { get; set; }
    public string Email { get; set; }
    public string Notes { get; set; }
    public bool IsPrimaryContact { get; set; }
}

我的映射器如下;

public sealed class CompanyMap : ClassMap<Company>
{
    public CompanyMap()
    {
        Map(m => m.Id).Name("ID");
        Map(m => m.Name).Name("Company");
        Map(m => m.Website).Name("WebPage");

        References<CompanyAddressFromCompanyMap>(m => m.Address);

        References<PrimaryContactFromCompanyMap>(m => m.Contacts);
    }
}

public sealed class CompanyAddressFromCompanyMap: ClassMap<Address>
{
    public CompanyAddressFromCompanyMap()
    {
        Map(m => m.Address1).Name("Address");
        Map(m => m.Town).Name("City");
        Map(m => m.Region).Name("State");
        Map(m => m.PostCode).Name("PostalCode");
        Map(m => m.Country).Name("Country");
        Map(m => m.IsPrimaryAddress).Default(true);
    }
}

public sealed class PrimaryContactFromCompanyMap : ClassMap<Contact>
{
    public PrimaryContactFromCompanyMap()
    {
        Map(m => m.FirstName).Name("FirstName");
        Map(m => m.LastName).Name("LastName");
        Map(m => m.HomeTelephone).Name("HomePhone");
        Map(m => m.BusinessTelephone).Name("BusinessPhone");
        Map(m => m.Mobile).Name("MobilePhone");
        Map(m => m.Email).Name("Email");
        Map(m => m.IsPrimaryContact).Default(true);
    }
}

但是这会引发错误;

System.ArgumentException: Property 'System.String FirstName' is not defined for type 'System.Collections.Generic.IList 1 [Contact]'(参数'property')`

我认为这可能是因为这是一个IList<Contact>

任何人都可以就错误提出建议,以及如何映射到嵌套集合?

c# csvhelper
1个回答
0
投票

这个问题很有趣。为了简化起见,我删除了某些csv字段。我刚刚在配置中注册了您的ClassMap,并使用了一个简单的Map(m => m.Contacts).ConvertUsing(...)。

我无法弄清楚如何使用TypeConverter,但这可能也可行。

可能最好是避免使用References 注册嵌套的classMap,而是直接在配置中注册它并使用简单的Map

这是完整的xunit测试示例。

    public class CsvHelper
    {
        internal string csv = @"
Company,Address,FirstName,AnotherName
MyCompany,MyAddress,MyFirstName,MyAnotherName
";
        public CsvHelper()
        {

        }

        [Fact]
        public void Stackoverflow()
        {
            using var r = new StringReader(csv);
            var conf = new CsvConfiguration(CultureInfo.InvariantCulture);
            conf.Delimiter = ",";
            conf.RegisterClassMap<CompanyMap>();
            conf.RegisterClassMap<PrimaryContactFromCompanyMap>();

            using var cr = new CsvReader(r, conf);
            var records = cr.GetRecords<Company>().ToList();
            Assert.True(records.Count == 1);
        }
    }

    public class Company
    {
        public string CompanyName { get; set; }
        public Address Address { get; set; }

        public IList<Contact> Contacts { get; set; }
    }

    public class Address
    {
        public string Address1 { get; set; }
    }


    public class Contact
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public sealed class CompanyMap : ClassMap<Company>
    {
        public CompanyMap()
        {
            Map(m => m.CompanyName).Name("Company");

            References<CompanyAddressFromCompanyMap>(m => m.Address);
            Map(m => m.Contacts).ConvertUsing(r =>
            {
                var c = r.GetRecord<Contact>();
                return new List<Contact>() { c };
            });
        }
    }

    public sealed class CompanyAddressFromCompanyMap : ClassMap<Address>
    {
        public CompanyAddressFromCompanyMap()
        {
            Map(m => m.Address1).Name("Address");
        }
    }

    public sealed class PrimaryContactFromCompanyMap : ClassMap<Contact>
    {
        public PrimaryContactFromCompanyMap()
        {
            Map(m => m.FirstName).Name("FirstName");
            Map(m => m.LastName).Name("AnotherName");
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.