CsvHelper文档-4映射
CsvHelper文档-4映射
类映射
有时候你的类成员和csv的header不一定对应,有时候你的csv文件根本就没有header行,你需要特别制定一个成员的index,你不能依靠.net中默认的顺序。在这些情况下,你可以创建一个类映射文件来映射类成员和csv文件字段。
为了创建一个类到csv文件的映射,你需要一个ClassMap
,你可以映射任何公共成员(属性或者字段);
public class MyClass
{
public int Id { get; set; }
public string Name { get; set; }
}
public sealed class MyClassMap : ClassMap<MyClass>
{
public MyClassMap()
{
Map( m => m.Id );
Map( m => m.Name );
}
}
(上面这个例子其实就是把类和文件做个默认对应,也就是说,按照顺序,第一个Id对应的是csv的第一个字段Id,类推。)
要使用这个映射文件,你需要在configuration中注册它
var csv = new CsvReader( textReader );
csv.Configuration.RegisterClassMap<MyClassMap>();
(Configuration可以做一些设置,后面再说)
引用映射
为了映射一个引用类型,你需要按照树结构引用成员就是了,深度没有限制。
public class A
{
public int Id { get; set; }
public B B { get; set; }
}
public class B
{
public int Id { get; set; }
public C C { get; set; }
}
public class C
{
public int Id { get; set; }
}
public sealed class AMap : ClassMap<A>
{
public AMap()
{
Map( m => m.Id ).Name( "A" );
Map( m => m.B.Id ).Name( "B" );
Map( m => m.B.C.Id).Name( "C" );
}
}
自动映射
如果你在没有创建映射字段的情况下进行读写,映射文件会自动的创建并自动的应用。自动映射会在对象成员和文件字段之间按照默认的映射设定创建映射关系。你可以通过configuration来改变一些默认设定。如果有循环引用,自动映射会停止这个结点的深入,继续下一个结点。
你可以在映射文件中直接调用AutoMap
方法,如果你只有少数几个需要自己映射的,你可以先用AutoMap来建立初始的映射,然后再手动将特殊的几个映射手动完成。
public class MyClass
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedDate { get; set; }
}
public sealed class MyClassMap : ClassMap<MyClass>
{
public MyClassMap()
{
AutoMap();
Map( m => m.CreatedDate ).Ignore();
}
}
选项
通过选项可以改变映射行为。
Name
可以指定Header的名称,读取的字段如果有多个名称,甚至可以制定多个名称。所有名称都会被检查一遍来查找对应的字段。写入的时候只会用到第一个字段。
// Single name
Map( m => m.Id ).Name( "id" );
// Multiple possible names
Map( m => m.Id ).Name( "id", "the_id", "Id" );
NameIndex
如果一个列名出现在多个列,可以在映射的时候直接指定这个列的Index(具体是相同Name的Index);
// Example header
id,name,id
// Mapping
Map( m => m.Id ).Name( "id" ).Index( 1 );
Index
如果根本就没有header,可以直接指定列的Index,如果有Name,则优先使用Name再考虑Index。写入的时候都可以指定,确保列的位置正确。
Map( m => m.Id ).Index( 0 );
Default
指定一个默认值,如果读取的位置字段是空的话;(相当于替代字符)
Map( m => m.Name ).Default( "empty" );
Constant
指定一个值作为读写字段的时候的常量,如此,使用这个值的时候会忽略映射设置。
Map( m => m.Name ).Constant( "never changes" );
Ignore
在读写的时候忽略某个字段;注意:如果一个成员已经被映射到一个引用成员,不管是用类映射文件,还是自动映射,调用这个方法都不会忽略所有已经被映射子成员。
Map( m => m.Name ).Ignore();
TypeConverter
当需要进行类型转换的时候,可以指定ITypeConverter
接口;
Map( m => m.Name ).TypeConverter( new MyConverter() );
Map( m => m.Name ).TypeConverter<MyConverter>();
ConvertUsing
可以指定一个转换字段到成员,转换成员到字段的表达式;
// Convert to member
Map( m => m.Aggregate ).ConvertUsing( row => row.Get<int>( "A" ) + row.Get<int>( "B" ) );
// Block
Map( m => m.Aggregate ).ConvertUsing( row =>
{
var a = row.Get<int>( "A" );
var b = row.Get<int>( "B" );
return a + b;
} );
// Convert to field
Map( m => m.Aggregate ).ConvertUsing( m => $"A + B = {m.A + m.B}" );
// Block
Map( m => m.Aggregate ).ConvertUsing( m =>
{
var field = "A + B = ";
field += ( m.A + m.B ).ToString();
return field;
} );
Validate
当读取的时候可以指定一个表达式来验证字段,如果表达式返回false,则抛出ValidationException异常。
Map( m => m.Number ).Validate( field => !string.IsNullOrEmpty( field ) );
// Log error instead of throwing an exception.
Map( m => m.Number ).Validate( field =>
{
var isValid = !string.IsNullOrEmpty( field );
if( !isValid )
{
logger.AppendLine( $"Field '{field}' is not valid!" );
}
return true;
} );```