Skip to content

Commit

Permalink
增加新的文档
Browse files Browse the repository at this point in the history
  • Loading branch information
yihango committed Jun 11, 2021
1 parent c221b9d commit 51e2af6
Show file tree
Hide file tree
Showing 28 changed files with 1,586 additions and 7 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@

## Documents



[中文文档](cn/README.md)

38 changes: 38 additions & 0 deletions cn/Async.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Async

### Async support

PM> Install-Package Mapster.Async

This plugin allows you to perform async operation for mapping

##### Setup

Use `AfterMappingAsync` to setup async operation

```csharp
config.NewConfig<Poco, Dto>()
.AfterMappingAsync(async (poco, dto) =>
{
var userManager = MapContext.Current.GetService<UserManager>();
var user = await userManager.FindByIdAsync(poco.UserId);
dto.UserName = user.Name;
});
```

##### Mapping

Then map asynchronously with `AdaptToTypeAsync`.

```csharp
var dto = await poco.BuildAdapter()
.AdaptToTypeAsync<Dto>();
```


Or like this, if you use mapper instance.

```csharp
var dto = await _mapper.From(poco)
.AdaptToTypeAsync<Dto>();
```
161 changes: 161 additions & 0 deletions cn/Attribute-base-Code-generation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# Attribute base Code generation

### Generate models

Annotate your class with `[AdaptFrom]`, `[AdaptTo]`, or `[AdaptTwoWays]`.

Example:
```csharp
[AdaptTo("[name]Dto")]
public class Student {
...
}
```

Then Mapster will generate:
```csharp
public class StudentDto {
...
}
```

#### Ignore some properties on generation

By default, code generation will ignore properties that annotated `[AdaptIgnore]` attribute. But you can add more settings which include `IgnoreAttributes`, `IgnoreNoAttributes`, `IgnoreNamespaces`.

Example:
```csharp
[AdaptTo("[name]Dto", IgnoreNoAttributes = new[] { typeof(DataMemberAttribute) })]
public class Student {

[DataMember]
public string Name { get; set; } //this property will be generated
public string LastName { get; set; } //this will not be generated
}
```

#### Change property types

By default, if property type annotated with the same adapt attribute, code generation will forward to that type. (For example, `Student` has `ICollection<Enrollment>`, after code generation `StudentDto` will has `ICollection<EnrollmentDto>`).

You can override this by `[PropertyType(typeof(Target))]` attribute. This annotation can be annotated to either on property or on class.

For example:
```csharp
[AdaptTo("[name]Dto")]
public class Student {
public ICollection<Enrollment> Enrollments { get; set; }
}

[AdaptTo("[name]Dto"), PropertyType(typeof(DataItem))]
public class Enrollment {
[PropertyType(typeof(string))]
public Grade? Grade { get; set; }
}
```

This will generate:
```csharp
public class StudentDto {
public ICollection<DataItem> Enrollments { get; set; }
}
public class EnrollmentDto {
public string Grade { get; set; }
}
```

#### Generate readonly properties

For `[AdaptTo]` and `[AdaptTwoWays]`, you can generate readonly properties with `MapToConstructor` setting.

For example:
```csharp
[AdaptTo("[name]Dto", MapToConstructor = true)]
public class Student {
public string Name { get; set; }
}
```

This will generate:
```csharp
public class StudentDto {
public string Name { get; }

public StudentDto(string name) {
this.Name = name;
}
}
```

#### Generate nullable properties

For `[AdaptFrom]`, you can generate nullable properties with `IgnoreNullValues` setting.

For example:
```csharp
[AdaptFrom("[name]Merge", IgnoreNullValues = true)]
public class Student {
public int Age { get; set; }
}
```

This will generate:
```csharp
public class StudentMerge {
public int? Age { get; set; }
}
```

### Generate extension methods

#### Generate using `[GenerateMapper]` attribute
For any POCOs annotate with `[AdaptFrom]`, `[AdaptTo]`, or `[AdaptTwoWays]`, you can add `[GenerateMapper]` in order to generate extension methods.

Example:
```csharp
[AdaptTo("[name]Dto"), GenerateMapper]
public class Student {
...
}
```

Then Mapster will generate:
```csharp
public class StudentDto {
...
}
public static class StudentMapper {
public static StudentDto AdaptToDto(this Student poco) { ... }
public static StudentDto AdaptTo(this Student poco, StudentDto dto) { ... }
public static Expression<Func<Student, StudentDto>> ProjectToDto => ...
}
```

#### Configuration
If you have configuration, it must be in `IRegister`

```csharp
public class MyRegister : IRegister
{
public void Register(TypeAdapterConfig config)
{
config.NewConfig<TSource, TDestination>();
}
}
```

#### Generate using configuration

You can also generate extension methods and add extra settings from configuration.

```csharp
public class MyRegister : IRegister
{
public void Register(TypeAdapterConfig config)
{
config.NewConfig<TSource, TDestination>()
.GenerateMapper(MapType.Map | MapType.MapToTarget);
}
}
```
2 changes: 2 additions & 0 deletions cn/Config-location.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# 配置位置

### 入口

映射配置应该只初始化并且只进行一次配置。因此在编写代码的时候不能将映射配置和映射调用放在同一个地方。
Expand Down
46 changes: 46 additions & 0 deletions cn/Custom-conversion-logic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Custom conversion logic

### Custom type conversion

In some cases, you may want to have complete control over how an object is mapped. You can register specific transformations using the `MapWith` method.

```csharp
//Example of transforming string to char[].
TypeAdapterConfig<string, char[]>.NewConfig()
.MapWith(str => str.ToCharArray());
```

`MapWith` also useful if you would like to copy instance rather than deep copy the object, for instance, `JObject` or `DbGeography`, these should treat as primitive types rather than POCO.

```csharp
TypeAdapterConfig<JObject, JObject>.NewConfig()
.MapWith(json => json);
```

In case you would like to combine `MapWith` with other settings, for example, `PreserveReference`, `Include`, or `AfterMapping`, you can pass `applySettings` to true.

```csharp
TypeAdapterConfig<ComplexPoco, ComplexDto>.NewConfig()
.PreserveReference(true)
.MapWith(poco => poco.ToDto(), applySettings: true);
```

### Custom mapping data to existing object

You can control mapping to existing object logic by `MapToTargetWith`. For example, you can copy data to existing array.

```csharp
TypeAdapterConfig<string[], string[]>.NewConfig()
.MapToTargetWith((src, dest) => Array.Copy(src, dest, src.Length));
```

NOTE: if you set `MapWith` setting but no `MapToTargetWith` setting, Mapster will use logic from `MapWith` setting.

### Custom actions after mapping

You might not need to specify custom mapping logic completely. You can let Mapster do the mapping, and you do logic where Mapster cannot cover by using `AfterMapping`.

```csharp
TypeAdapterConfig<Poco, Dto>.NewConfig()
.AfterMapping((src, dest) => SpecialSetFn(src, dest));
```
106 changes: 106 additions & 0 deletions cn/Custom-mapping.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Custom mapping

### Custom member mapping

You can customize how Mapster maps values to a property.

```csharp
TypeAdapterConfig<TSource, TDestination>
.NewConfig()
.Map(dest => dest.FullName,
src => string.Format("{0} {1}", src.FirstName, src.LastName));
```

You can even map when source and destination property types are different.

```csharp
TypeAdapterConfig<TSource, TDestination>
.NewConfig()
.Map(dest => dest.Gender, //Genders.Male or Genders.Female
src => src.GenderString); //"Male" or "Female"
```

### Mapping with condition

The Map configuration can accept a third parameter that provides a condition based on the source.
If the condition is not met, Mapster will retry with next conditions. Default condition should be added at the end without specifying condition. If you do not specify default condition, null or default value will be assigned.

```csharp
TypeAdapterConfig<TSource, TDestination>
.NewConfig()
.Map(dest => dest.FullName, src => "Sig. " + src.FullName, srcCond => srcCond.Country == "Italy")
.Map(dest => dest.FullName, src => "Sr. " + src.FullName, srcCond => srcCond.Country == "Spain")
.Map(dest => dest.FullName, src => "Mr. " + src.FullName);
```

NOTE: if you would like to skip mapping, when condition is met, you can use `IgnoreIf` (https://github.com/MapsterMapper/Mapster/wiki/Ignoring-members#ignore-conditionally).

### Mapping to non-public members

`Map` command can map to private member by specify name of the members.

```csharp
TypeAdapterConfig<TSource, TDestination>
.NewConfig()
.Map("PrivateDestName", "PrivateSrcName");
```

For more information about mapping non-public members, please see https://github.com/MapsterMapper/Mapster/wiki/Mapping-non-public-members.

### Deep destination property

`Map` can be defined to map deep destination property.

```csharp
TypeAdapterConfig<Poco, Dto>.NewConfig()
.Map(dest => dest.Child.Name, src => src.Name);
```

### Null propagation

If `Map` contains only property path, null propagation will be applied.

```csharp
TypeAdapterConfig<Poco, Dto>.NewConfig()
.Map(dest => dest.Name, src => src.Child.Name);
```

From above example, if `src.Child` is null, mapping will return null instead of throw `NullPointerException`.

### Multiple sources

**Example 1**: Include property to Poco

```csharp
public class SubDto
{
public string Extra { get; set; }
}
public class Dto
{
public string Name { get; set; }
public SubDto SubDto { get; set; }
}
public class Poco
{
public string Name { get; set; }
public string Extra { get; set; }
}
```

In this case, you would like to map all properties from `Dto` to `Poco`, and also include all properties from `Dto.SubDto` to `Poco`. You can do this by just mapping `dto.SubDto` to `poco` in configuration.

```csharp
TypeAdapterConfig<Dto, Poco>.NewConfig()
.Map(poco => poco, dto => dto.SubDto);
```

**Example 2**: Mapping 2 objects to poco

In this example, you have `Dto1` and `Dto2`, and you would like to map both objects to a `Poco`. You can do this by wrapping `Dto1` and `Dto2` into a tuple. And then mapping `tuple.Item1` and `tuple.Item2` to `Poco`.

```csharp
TypeAdapterConfig<(Dto1, Dto2), Poco>.NewConfig()
.Map(dest => dest, src => src.Item1)
.Map(dest => dest, src => src.Item2);
```
Loading

0 comments on commit 51e2af6

Please sign in to comment.