mirror of https://github.com/abpframework/abp
				
				
				
			
						commit
						50575289b8
					
				| @ -1,3 +0,0 @@ | ||||
| ## AutoMapper Integration | ||||
| 
 | ||||
| TODO | ||||
| @ -1,3 +1,365 @@ | ||||
| # Object Extensions | ||||
| 
 | ||||
| TODO | ||||
| ABP Framework provides an **object extension system** to allow you to **add extra properties** to an existing object **without modifying** the related class. This allows to extend functionalities implemented by a depended [application module](Modules/Index.md), especially when you want to [extend entities](Customizing-Application-Modules-Extending-Entities.md) and [DTOs](Customizing-Application-Modules-Overriding-Services.md) defined by the module. | ||||
| 
 | ||||
| > Object extension system is not normally not needed for your own objects since you can easily add regular properties to your own classes. | ||||
| 
 | ||||
| ## IHasExtraProperties Interface | ||||
| 
 | ||||
| This is the interface to make a class extensible. It simply defines a `Dictionary` property: | ||||
| 
 | ||||
| ````csharp | ||||
| Dictionary<string, object> ExtraProperties { get; } | ||||
| ```` | ||||
| 
 | ||||
| Then you can add or get extra properties using this dictionary. | ||||
| 
 | ||||
| ### Base Classes | ||||
| 
 | ||||
| `IHasExtraProperties` interface is implemented by several base classes by default: | ||||
| 
 | ||||
| * Implemented by the `AggregateRoot` class (see [entities](Entities.md)). | ||||
| * Implemented by `ExtensibleEntityDto`, `ExtensibleAuditedEntityDto`... base [DTO](Data-Transfer-Objects.md) classes. | ||||
| * Implemented by the `ExtensibleObject`, which is a simple base class can be inherited for any type of object. | ||||
| 
 | ||||
| So, if you inherit from these classes, your class will also be extensible. If not, you can always implement it manually. | ||||
| 
 | ||||
| ### Fundamental Extension Methods | ||||
| 
 | ||||
| While you can directly use the `ExtraProperties` property of a class, it is suggested to use the following extension methods while working with the extra properties. | ||||
| 
 | ||||
| #### SetProperty | ||||
| 
 | ||||
| Used to set the value of an extra property: | ||||
| 
 | ||||
| ````csharp | ||||
| user.SetProperty("Title", "My Title"); | ||||
| user.SetProperty("IsSuperUser", true); | ||||
| ```` | ||||
| 
 | ||||
| `SetProperty` returns the same object, so you can chain it: | ||||
| 
 | ||||
| ````csharp | ||||
| user.SetProperty("Title", "My Title") | ||||
|     .SetProperty("IsSuperUser", true); | ||||
| ```` | ||||
| 
 | ||||
| #### GetProperty | ||||
| 
 | ||||
| Used to read the value of an extra property: | ||||
| 
 | ||||
| ````csharp | ||||
| var title = user.GetProperty<string>("Title"); | ||||
| 
 | ||||
| if (user.GetProperty<bool>("IsSuperUser")) | ||||
| { | ||||
|     //... | ||||
| } | ||||
| ```` | ||||
| 
 | ||||
| * `GetProperty` is a generic method and takes the object type as the generic parameter. | ||||
| * Returns the default value if given property was not set before (default value is `0` for `int`, `false` for `bool`... etc). | ||||
| 
 | ||||
| ##### Non Primitive Property Types | ||||
| 
 | ||||
| If your property type is not a primitive (int, bool, enum, string... etc) type, then you need to use non-generic version of the `GetProperty` which returns an `object`. | ||||
| 
 | ||||
| #### HasProperty | ||||
| 
 | ||||
| Used to check if the object has a property set before. | ||||
| 
 | ||||
| #### RemoveProperty | ||||
| 
 | ||||
| Used to remove a property from the object. Use this methods instead of setting a `null` value for the property. | ||||
| 
 | ||||
| ### Some Best Practices | ||||
| 
 | ||||
| Using magic strings for the property names is dangerous since you can easily type the property name wrong - it is not type safe. Instead; | ||||
| 
 | ||||
| * Define a constant for your extra property names | ||||
| * Create extension methods to easily set your extra properties. | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| ````csharp | ||||
| public static class IdentityUserExtensions | ||||
| { | ||||
|     private const string TitlePropertyName = "Title"; | ||||
| 
 | ||||
|     public static void SetTitle(this IdentityUser user, string title) | ||||
|     { | ||||
|         user.SetProperty(TitlePropertyName, title); | ||||
|     } | ||||
| 
 | ||||
|     public static string GetTitle(this IdentityUser user) | ||||
|     { | ||||
|         return user.GetProperty<string>(TitlePropertyName); | ||||
|     } | ||||
| } | ||||
| ```` | ||||
| 
 | ||||
| Then you can easily set or get the `Title` property: | ||||
| 
 | ||||
| ````csharp | ||||
| user.SetTitle("My Title"); | ||||
| var title = user.GetTitle(); | ||||
| ```` | ||||
| 
 | ||||
| ## Object Extension Manager | ||||
| 
 | ||||
| While you can set arbitrary properties to an extensible object (which implements the `IHasExtraProperties` interface), `ObjectExtensionManager` is used to explicitly define extra properties for extensible classes. | ||||
| 
 | ||||
| Explicitly defining an extra property has some use cases: | ||||
| 
 | ||||
| * Allows to control how the extra property is handled on object to object mapping (see the section below). | ||||
| * Allows to define metadata for the property. For example, you can map an extra property to a table field in the database while using the [EF Core](Entity-Framework-Core.md). | ||||
| 
 | ||||
| > `ObjectExtensionManager` implements the singleton pattern (`ObjectExtensionManager.Instance`) and you should define object extensions before your application startup. The [application startup template](Startup-Templates/Application.md) has some pre-defined static classes to safely define object extensions inside. | ||||
| 
 | ||||
| ### AddOrUpdate | ||||
| 
 | ||||
| `AddOrUpdate` is the main method to define a extra properties or update extra properties for an object. | ||||
| 
 | ||||
| Example: Define extra properties for the `IdentityUser` entity: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdate<IdentityUser>(options => | ||||
|         { | ||||
|             options.AddOrUpdateProperty<string>("SocialSecurityNumber"); | ||||
|             options.AddOrUpdateProperty<bool>("IsSuperUser"); | ||||
|         } | ||||
|     ); | ||||
| ```` | ||||
| 
 | ||||
| ### AddOrUpdateProperty | ||||
| 
 | ||||
| While `AddOrUpdateProperty` can be used on the `options` as shown before, if you want to define a single extra property, you can use the shortcut extension method too: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdateProperty<IdentityUser, string>("SocialSecurityNumber"); | ||||
| ```` | ||||
| 
 | ||||
| Sometimes it would be practical to define a single extra property to multiple types. Instead of defining one by one, you can use the following code: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdateProperty<string>( | ||||
|         new[] | ||||
|         { | ||||
|             typeof(IdentityUserDto), | ||||
|             typeof(IdentityUserCreateDto), | ||||
|             typeof(IdentityUserUpdateDto) | ||||
|         }, | ||||
|         "SocialSecurityNumber" | ||||
|     ); | ||||
| ```` | ||||
| 
 | ||||
| ### Property Configuration | ||||
| 
 | ||||
| `AddOrUpdateProperty` can also get an action that can perform additional configuration on the property definition: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdateProperty<IdentityUser, string>( | ||||
|         "SocialSecurityNumber", | ||||
|         options => | ||||
|         { | ||||
|             //Configure options... | ||||
|         }); | ||||
| ```` | ||||
| 
 | ||||
| > `options` has a dictionary, named `Configuration` which makes the object extension definitions even extensible. It is used by the EF Core to map extra properties to table fields in the database. See the [extending entities](Customizing-Application-Modules-Extending-Entities.md) document. | ||||
| 
 | ||||
| The following sections explain the fundamental property configuration options. | ||||
| 
 | ||||
| #### CheckPairDefinitionOnMapping | ||||
| 
 | ||||
| Controls how to check property definitions while mapping two extensible objects. See the "Object to Object Mapping" section to understand the `CheckPairDefinitionOnMapping` option better. | ||||
| 
 | ||||
| ## Validation | ||||
| 
 | ||||
| You may want to add some **validation rules** for the extra properties you've defined. `AddOrUpdateProperty` method options allows two ways of performing validation: | ||||
| 
 | ||||
| 1. You can add **data annotation attributes** for a property. | ||||
| 2. You can write an action (code block) to perform a **custom validation**. | ||||
| 
 | ||||
| Validation works when you use the object in a method that is **automatically validated** (e.g. controller actions, page handler methods, application service methods...). So, all extra properties are validated whenever the extended object is being validated. | ||||
| 
 | ||||
| ### Data Annotation Attributes | ||||
| 
 | ||||
| All of the standard data annotation attributes are valid for extra properties. Example: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdateProperty<IdentityUserCreateDto, string>( | ||||
|         "SocialSecurityNumber", | ||||
|         options => | ||||
|         { | ||||
|             options.ValidationAttributes.Add(new RequiredAttribute()); | ||||
|             options.ValidationAttributes.Add( | ||||
|                 new StringLengthAttribute(32) { | ||||
|                     MinimumLength = 6  | ||||
|                 } | ||||
|             ); | ||||
|         }); | ||||
| ```` | ||||
| 
 | ||||
| With this configuration, `IdentityUserCreateDto` objects will be invalid without a valid `SocialSecurityNumber` value provided. | ||||
| 
 | ||||
| ### Custom Validation | ||||
| 
 | ||||
| If you need, you can add a custom action that is executed to validate the extra properties. Example: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdateProperty<IdentityUserCreateDto, string>( | ||||
|         "SocialSecurityNumber", | ||||
|         options => | ||||
|         { | ||||
|             options.Validators.Add(context => | ||||
|             { | ||||
|                 var socialSecurityNumber = context.Value as string; | ||||
| 
 | ||||
|                 if (socialSecurityNumber == null || | ||||
|                     socialSecurityNumber.StartsWith("X")) | ||||
|                 { | ||||
|                     context.ValidationErrors.Add( | ||||
|                         new ValidationResult( | ||||
|                             "Invalid social security number: " + socialSecurityNumber, | ||||
|                             new[] { "SocialSecurityNumber" } | ||||
|                         ) | ||||
|                     ); | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
| ```` | ||||
| 
 | ||||
| `context.ServiceProvider` can be used to resolve a service dependency for advanced scenarios. | ||||
| 
 | ||||
| In addition to add custom validation logic for a single property, you can add a custom validation logic that is executed in object level. Example: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
| .AddOrUpdate<IdentityUserCreateDto>(objConfig => | ||||
| { | ||||
|     //Define two properties with their own validation rules | ||||
|      | ||||
|     objConfig.AddOrUpdateProperty<string>("Password", propertyConfig => | ||||
|     { | ||||
|         propertyConfig.ValidationAttributes.Add(new RequiredAttribute()); | ||||
|     }); | ||||
| 
 | ||||
|     objConfig.AddOrUpdateProperty<string>("PasswordRepeat", propertyConfig => | ||||
|     { | ||||
|         propertyConfig.ValidationAttributes.Add(new RequiredAttribute()); | ||||
|     }); | ||||
| 
 | ||||
|     //Write a common validation logic works on multiple properties | ||||
|      | ||||
|     objConfig.Validators.Add(context => | ||||
|     { | ||||
|         if (context.ValidatingObject.GetProperty<string>("Password") != | ||||
|             context.ValidatingObject.GetProperty<string>("PasswordRepeat")) | ||||
|         { | ||||
|             context.ValidationErrors.Add( | ||||
|                 new ValidationResult( | ||||
|                     "Please repeat the same password!", | ||||
|                     new[] { "Password", "PasswordRepeat" } | ||||
|                 ) | ||||
|             ); | ||||
|         } | ||||
|     }); | ||||
| }); | ||||
| ```` | ||||
| 
 | ||||
| ## Object to Object Mapping | ||||
| 
 | ||||
| Assume that you've added an extra property to an extensible entity object and used auto [object to object mapping](Object-To-Object-Mapping.md) to map this entity to an extensible DTO class. You need to be careful in such a case, because the extra property may contain a **sensitive data** that should not be available to clients. | ||||
| 
 | ||||
| This section offers some **good practices** to control your extra properties on object mapping. | ||||
| 
 | ||||
| ### MapExtraPropertiesTo | ||||
| 
 | ||||
| `MapExtraPropertiesTo` is an extension method provided by the ABP Framework to copy extra properties from an object to another in a controlled manner. Example usage: | ||||
| 
 | ||||
| ````csharp | ||||
| identityUser.MapExtraPropertiesTo(identityUserDto); | ||||
| ```` | ||||
| 
 | ||||
| `MapExtraPropertiesTo` **requires to define properties** (as described above) in **both sides** (`IdentityUser` and `IdentityUserDto` in this case) in order to copy the value to the target object. Otherwise, it doesn't copy the value even if it does exists in the source object (`identityUser` in this example). There are some ways to overload this restriction. | ||||
| 
 | ||||
| #### MappingPropertyDefinitionChecks | ||||
| 
 | ||||
| `MapExtraPropertiesTo` gets an additional parameter to control the definition check for a single mapping operation: | ||||
| 
 | ||||
| ````csharp | ||||
| identityUser.MapExtraPropertiesTo( | ||||
|     identityUserDto, | ||||
|     MappingPropertyDefinitionChecks.None | ||||
| ); | ||||
| ```` | ||||
| 
 | ||||
| > Be careful since `MappingPropertyDefinitionChecks.None` copies all extra properties without any check. `MappingPropertyDefinitionChecks` enum has other members too. | ||||
| 
 | ||||
| If you want to completely disable definition check for a property, you can do it while defining the extra property (or update an existing definition) as shown below: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdateProperty<IdentityUser, string>( | ||||
|         "SocialSecurityNumber", | ||||
|         options => | ||||
|         { | ||||
|             options.CheckPairDefinitionOnMapping = false; | ||||
|         }); | ||||
| ```` | ||||
| 
 | ||||
| #### Ignored Properties | ||||
| 
 | ||||
| You may want to ignore some properties on a specific mapping operation: | ||||
| 
 | ||||
| ````csharp | ||||
| identityUser.MapExtraPropertiesTo( | ||||
|     identityUserDto, | ||||
|     ignoredProperties: new[] {"MySensitiveProp"} | ||||
| ); | ||||
| ```` | ||||
| 
 | ||||
| Ignored properties are not copied to the target object. | ||||
| 
 | ||||
| #### AutoMapper Integration | ||||
| 
 | ||||
| If you're using the [AutoMapper](https://automapper.org/) library, the ABP Framework also provides an extension method to utilize the `MapExtraPropertiesTo` method defined above. | ||||
| 
 | ||||
| You can use the `MapExtraProperties()` method inside your mapping profile. | ||||
| 
 | ||||
| ````csharp | ||||
| public class MyProfile : Profile | ||||
| { | ||||
|     public MyProfile() | ||||
|     { | ||||
|         CreateMap<IdentityUser, IdentityUserDto>() | ||||
|             .MapExtraProperties(); | ||||
|     } | ||||
| } | ||||
| ```` | ||||
| 
 | ||||
| It has the same parameters with the `MapExtraPropertiesTo` method. | ||||
| 
 | ||||
| ## Entity Framework Core Database Mapping | ||||
| 
 | ||||
| If you're using the EF Core, you can map an extra property to a table field in the database. Example: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdateProperty<IdentityUser, string>( | ||||
|         "SocialSecurityNumber", | ||||
|         options => | ||||
|         { | ||||
|             options.MapEfCore(b => b.HasMaxLength(32)); | ||||
|         } | ||||
|     ); | ||||
| ```` | ||||
| 
 | ||||
| See the [Entity Framework Core Integration document](Entity-Framework-Core.md) for more. | ||||
| @ -1,3 +0,0 @@ | ||||
| ## AutoMapper Integration | ||||
| 
 | ||||
| TODO | ||||
| @ -0,0 +1,267 @@ | ||||
| # 对象扩展 | ||||
| 
 | ||||
| ABP框架提供了 **实体扩展系统** 允许你 **添加额外属性** 到已存在的对象 **无需修改相关类**. 它允许你扩展[应用程序依赖模块](Modules/Index.md)实现的功能,尤其是当你要扩展[模块定义的实体](Customizing-Application-Modules-Extending-Entities.md)和[DTO](Customizing-Application-Modules-Overriding-Services.md)时. | ||||
| 
 | ||||
| > 你自己的对象通常不需要对象扩展系统,因为你可以轻松的添加常规属性到你的类中. | ||||
| 
 | ||||
| ## IHasExtraProperties 接口 | ||||
| 
 | ||||
| 这是一个使类可扩展的接口. 它定义了 `Dictionary` 属性: | ||||
| 
 | ||||
| ````csharp | ||||
| Dictionary<string, object> ExtraProperties { get; } | ||||
| ```` | ||||
| 
 | ||||
| 然后你可以使用此字典添加或获取其他属性. | ||||
| 
 | ||||
| ### 基类 | ||||
| 
 | ||||
| 默认以下基类实现了 `IHasExtraProperties` 接口: | ||||
| 
 | ||||
| * 由 `AggregateRoot` 类实现 (参阅 [entities](Entities.md)). | ||||
| * 由 `ExtensibleEntityDto`, `ExtensibleAuditedEntityDto`... [DTO](Data-Transfer-Objects.md)基类实现. | ||||
| * 由 `ExtensibleObject` 实现, 它是一个简单的基类,任何类型的对象都可以继承. | ||||
| 
 | ||||
| 如果你的类从这些类继承,那么你的类也是可扩展的,如果没有,你也可以随时手动继承. | ||||
| 
 | ||||
| ### 基本扩展方法 | ||||
| 
 | ||||
| 虽然可以直接使用类的 `ExtraProperties` 属性,但建议使用以下扩展方法使用额外属性. | ||||
| 
 | ||||
| #### SetProperty | ||||
| 
 | ||||
| 用于设置额外属性值: | ||||
| 
 | ||||
| ````csharp | ||||
| user.SetProperty("Title", "My Title"); | ||||
| user.SetProperty("IsSuperUser", true); | ||||
| ```` | ||||
| 
 | ||||
| `SetProperty` 返回相同的对象, 你可以使用链式编程: | ||||
| 
 | ||||
| ````csharp | ||||
| user.SetProperty("Title", "My Title") | ||||
|     .SetProperty("IsSuperUser", true); | ||||
| ```` | ||||
| 
 | ||||
| #### GetProperty | ||||
| 
 | ||||
| 用于读取额外属性的值: | ||||
| 
 | ||||
| ````csharp | ||||
| var title = user.GetProperty<string>("Title"); | ||||
| 
 | ||||
| if (user.GetProperty<bool>("IsSuperUser")) | ||||
| { | ||||
|     //... | ||||
| } | ||||
| ```` | ||||
| 
 | ||||
| * `GetProperty` 是一个泛型方法,对象类型做为泛型参数. | ||||
| * 如果未设置给定的属性,则返回默认值 (`int` 的默认值为 `0` ,  `bool` 的默认值是 `false` ... 等). | ||||
| 
 | ||||
| ##### 非基本属性类型 | ||||
| 
 | ||||
| 如果您的属性类型不是原始类型(int,bool,枚举,字符串等),你需要使用 `GetProperty` 的非泛型版本,它会返回 `object`. | ||||
| 
 | ||||
| #### HasProperty | ||||
| 
 | ||||
| 用于检查对象之前是否设置了属性. | ||||
| 
 | ||||
| #### RemoveProperty | ||||
| 
 | ||||
| 用于从对象中删除属性. 使用此方法代替为属性设置 `null` 值. | ||||
| 
 | ||||
| ### 一些最佳实践 | ||||
| 
 | ||||
| 为属性名称使用魔术字符串很危险,因为你很容易输入错误的属性名称-这并不安全; | ||||
| 
 | ||||
| * 为你的额外属性名称定义一个常量. | ||||
| * 使用扩展方法轻松设置你的属性. | ||||
| 
 | ||||
| 示例: | ||||
| 
 | ||||
| ````csharp | ||||
| public static class IdentityUserExtensions | ||||
| { | ||||
|     private const string TitlePropertyName = "Title"; | ||||
| 
 | ||||
|     public static void SetTitle(this IdentityUser user, string title) | ||||
|     { | ||||
|         user.SetProperty(TitlePropertyName, title); | ||||
|     } | ||||
| 
 | ||||
|     public static string GetTitle(this IdentityUser user) | ||||
|     { | ||||
|         return user.GetProperty<string>(TitlePropertyName); | ||||
|     } | ||||
| } | ||||
| ```` | ||||
| 
 | ||||
| 然后, 你可以很容易地设置或获取 `Title` 属性: | ||||
| 
 | ||||
| ````csharp | ||||
| user.SetTitle("My Title"); | ||||
| var title = user.GetTitle(); | ||||
| ```` | ||||
| 
 | ||||
| ## Object Extension Manager | ||||
| 
 | ||||
| 你可以为可扩展对象(实现 `IHasExtraProperties`接口)设置任意属性,  `ObjectExtensionManager` 用于显式定义可扩展类的其他属性. | ||||
| 
 | ||||
| 显式定义额外的属性有一些用例: | ||||
| 
 | ||||
| * 允许控制如何在对象到对象的映射上处理额外的属性 (参阅下面的部分). | ||||
| * 允许定义属性的元数据. 例如你可以在使用[EF Core](Entity-Framework-Core.md)时将额外的属性映射到数据库中的表字段. | ||||
| 
 | ||||
| > `ObjectExtensionManager` 实现单例模式 (`ObjectExtensionManager.Instance`) ,你应该在应用程序启动之前定义对象扩展. [应用程序启动模板](Startup-Templates/Application.md) 有一些预定义的静态类,可以安全在内部定义对象扩展. | ||||
| 
 | ||||
| ### AddOrUpdate | ||||
| 
 | ||||
| `AddOrUpdate` 是定义对象额外属性或更新对象额外属性的主要方法. | ||||
| 
 | ||||
| 示例: 为 `IdentityUser` 实体定义额外属性: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdate<IdentityUser>(options => | ||||
|         { | ||||
|             options.AddOrUpdateProperty<string>("SocialSecurityNumber"); | ||||
|             options.AddOrUpdateProperty<bool>("IsSuperUser"); | ||||
|         } | ||||
|     ); | ||||
| ```` | ||||
| 
 | ||||
| ### AddOrUpdateProperty | ||||
| 
 | ||||
| 虽然可以如上所示使用 `AddOrUpdateProperty`, 但如果要定义单个额外的属性,也可以使用快捷的扩展方法: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdateProperty<IdentityUser, string>("SocialSecurityNumber"); | ||||
| ```` | ||||
| 
 | ||||
| 有时将单个额外属性定义为多种类型是可行的. 你可以使用以下代码,而不是一个一个地定义: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdateProperty<string>( | ||||
|         new[] | ||||
|         { | ||||
|             typeof(IdentityUserDto), | ||||
|             typeof(IdentityUserCreateDto), | ||||
|             typeof(IdentityUserUpdateDto) | ||||
|         }, | ||||
|         "SocialSecurityNumber" | ||||
|     ); | ||||
| ```` | ||||
| 
 | ||||
| #### 属性配置 | ||||
| 
 | ||||
| `AddOrUpdateProperty` 还可以为属性定义执行其他配置的操作. | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdateProperty<IdentityUser, string>( | ||||
|         "SocialSecurityNumber", | ||||
|         options => | ||||
|         { | ||||
|             options.CheckPairDefinitionOnMapping = false; | ||||
|         }); | ||||
| ```` | ||||
| 
 | ||||
| > 参阅 "对象到对象映射" 部分了解 `CheckPairDefinitionOnMapping` 选项. | ||||
| 
 | ||||
| `options` 有一个名为 `Configuration` 的字典,该字典存储对象扩展定义甚至可以扩展. EF Core使用它来将其他属性映射到数据库中的表字段. 请参阅[扩展实体文档](Customizing-Application-Modules-Extending-Entities.md). | ||||
| 
 | ||||
| ## 对象到对象映射 | ||||
| 
 | ||||
| 假设你已向可扩展的实体对象添加了额外的属性并使用了自动[对象到对象的映射](Object-To-Object-Mapping.md)将该实体映射到可扩展的DTO类. 在这种情况下你需要格外小心,因为额外属性可能包含**敏感数据**,这些数据对于客户端不可用. | ||||
| 
 | ||||
| 本节提供了一些**好的做法**,可以控制对象映射的额外属性。 | ||||
| 
 | ||||
| ### MapExtraPropertiesTo | ||||
| 
 | ||||
| `MapExtraPropertiesTo` 是ABP框架提供的扩展方法,用于以受控方式将额外的属性从一个对象复制到另一个对象. 示例: | ||||
| 
 | ||||
| ````csharp | ||||
| identityUser.MapExtraPropertiesTo(identityUserDto); | ||||
| ```` | ||||
| 
 | ||||
| `MapExtraPropertiesTo` 需要在**两侧**(本例中是`IdentityUser` 和 `IdentityUserDto`)**定义属性**. 以将值复制到目标对象. 否则即使源对象(在此示例中为 `identityUser` )中确实存在该值,它也不会复制. 有一些重载此限制的方法. | ||||
| 
 | ||||
| #### MappingPropertyDefinitionChecks | ||||
| 
 | ||||
| `MapExtraPropertiesTo` 获取一个附加参数来控制单个映射操作的定义检查: | ||||
| 
 | ||||
| ````csharp | ||||
| identityUser.MapExtraPropertiesTo( | ||||
|     identityUserDto, | ||||
|     MappingPropertyDefinitionChecks.None | ||||
| ); | ||||
| ```` | ||||
| 
 | ||||
| > 要小心,因为 `MappingPropertyDefinitionChecks.None` 会复制所有的额外属性而不进行任何检查. `MappingPropertyDefinitionChecks` 枚举还有其他成员. | ||||
| 
 | ||||
| 如果要完全禁用属性的定义检查,可以在定义额外的属性(或更新现有定义)时进行,如下所示: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdateProperty<IdentityUser, string>( | ||||
|         "SocialSecurityNumber", | ||||
|         options => | ||||
|         { | ||||
|             options.CheckPairDefinitionOnMapping = false; | ||||
|         }); | ||||
| ```` | ||||
| 
 | ||||
| #### 忽略属性 | ||||
| 
 | ||||
| 你可能要在映射操作忽略某些属性: | ||||
| 
 | ||||
| ````csharp | ||||
| identityUser.MapExtraPropertiesTo( | ||||
|     identityUserDto, | ||||
|     ignoredProperties: new[] {"MySensitiveProp"} | ||||
| ); | ||||
| ```` | ||||
| 
 | ||||
| 忽略的属性不会复制到目标对象. | ||||
| 
 | ||||
| #### AutoMapper集成 | ||||
| 
 | ||||
| 如果您使用的是[AutoMapper](https://automapper.org/)库,ABP框架还提供了一种扩展方法来利用上面定义的 `MapExtraPropertiesTo` 方法. | ||||
| 
 | ||||
| 你可以在映射配置文件中使用 `MapExtraProperties()` 方法. | ||||
| 
 | ||||
| ````csharp | ||||
| public class MyProfile : Profile | ||||
| { | ||||
|     public MyProfile() | ||||
|     { | ||||
|         CreateMap<IdentityUser, IdentityUserDto>() | ||||
|             .MapExtraProperties(); | ||||
|     } | ||||
| } | ||||
| ```` | ||||
| 
 | ||||
| 它与 `MapExtraPropertiesTo()` 方法具有相同的参数。 | ||||
| 
 | ||||
| ## Entity Framework Core 数据库映射 | ||||
| 
 | ||||
| 如果你使用的是EF Core,可以将额外的属性映射到数据库中的表字段. 例: | ||||
| 
 | ||||
| ````csharp | ||||
| ObjectExtensionManager.Instance | ||||
|     .AddOrUpdateProperty<IdentityUser, string>( | ||||
|         "SocialSecurityNumber", | ||||
|         options => | ||||
|         { | ||||
|             options.MapEfCore(b => b.HasMaxLength(32)); | ||||
|         } | ||||
|     ); | ||||
| ```` | ||||
| 
 | ||||
| 参阅 [Entity Framework Core 集成文档](Entity-Framework-Core.md) 了解更多内容. | ||||
| @ -0,0 +1,3 @@ | ||||
| # ABP ASP.NET Core UI Datatables.Net 集成 | ||||
| 
 | ||||
| TODO | ||||
											
												
													File diff suppressed because it is too large
													Load Diff
												
											
										
									
								| @ -1,7 +1,12 @@ | ||||
| using JetBrains.Annotations; | ||||
| 
 | ||||
| namespace Volo.Abp.Minify | ||||
| { | ||||
|     public interface IMinifier | ||||
|     { | ||||
|         string Minify(string source, string fileName = null); | ||||
|         string Minify( | ||||
|             string source, | ||||
|             [CanBeNull] string fileName = null, | ||||
|             [CanBeNull] string originalFileName = null); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,63 @@ | ||||
| { | ||||
|   "culture": "sl", | ||||
|   "texts": { | ||||
|     "InternalServerErrorMessage": "Zgodila se je napaka na strežniku!", | ||||
|     "ValidationErrorMessage": "Vaš zahtevek ni veljaven!", | ||||
|     "ValidationNarrativeErrorMessageTitle": "Pri preverjanju so bile zaznane sledeče napake.", | ||||
|     "DefaultErrorMessage": "Zgodila se je napaka!", | ||||
|     "DefaultErrorMessageDetail": "Strežnik ni poslal podrobnosti o napaki.", | ||||
|     "DefaultErrorMessage401": "Niste prijavljeni!", | ||||
|     "DefaultErrorMessage401Detail": "Za izvedbo te operacije se morate prijaviti.", | ||||
|     "DefaultErrorMessage403": "Nimate pravic!", | ||||
|     "DefaultErrorMessage403Detail": "Nimate dovoljenja za izvedbo te operacije!", | ||||
|     "DefaultErrorMessage404": "Vir ni bil najden!", | ||||
|     "DefaultErrorMessage404Detail": "Zahtevanega vira ni bilo mogoče najti na strežniku!", | ||||
|     "EntityNotFoundErrorMessage": "Ni entitete {0} z id-jem = {1}!", | ||||
|     "Languages": "Jeziki", | ||||
|     "Error": "Napaka", | ||||
|     "AreYouSure": "Ali ste prepričani?", | ||||
|     "Cancel": "Prekliči", | ||||
|     "Yes": "Da", | ||||
|     "No": "Ne", | ||||
|     "Ok": "V redu", | ||||
|     "Close": "Zapri", | ||||
|     "Save": "Shrani", | ||||
|     "SavingWithThreeDot": "Shranjujem...", | ||||
|     "Actions": "Dejanja", | ||||
|     "Delete": "Izbriši", | ||||
|     "Edit": "Uredi", | ||||
|     "Refresh": "Osveži", | ||||
|     "Language": "Jezik", | ||||
|     "LoadMore": "Naloži več", | ||||
|     "ProcessingWithThreeDot": "Procesiram...", | ||||
|     "LoadingWithThreeDot": "Nalagam...", | ||||
|     "Welcome": "Dobrodošli", | ||||
|     "Login": "Prijava", | ||||
|     "Register": "Registracija", | ||||
|     "Logout": "Odjava", | ||||
|     "Submit": "Pošlji", | ||||
|     "Back": "Nazaj", | ||||
|     "PagerSearch": "Iskanje", | ||||
|     "PagerNext": "Naslednja", | ||||
|     "PagerPrevious": "Prejšnja", | ||||
|     "PagerFirst": "Prva", | ||||
|     "PagerLast": "Zadnja", | ||||
|     "PagerInfo": "Prikazanih _START_ do _END_ od _TOTAL_ zapisov", | ||||
|     "PagerInfo{0}{1}{2}": "Prikazanih {0} do {1} od {2} zapisov", | ||||
|     "PagerInfoEmpty": "Prikazanih 0 do 0 od 0 zapisov", | ||||
|     "PagerInfoFiltered": "(filtrirano od vseh _MAX_ zapisov)", | ||||
|     "NoDataAvailableInDatatable": "V tabeli ni na voljo podatkov", | ||||
|     "PagerShowMenuEntries": "Prikaži _MENU_ zapise", | ||||
|     "DatatableActionDropdownDefaultText": "Dejanja", | ||||
|     "ChangePassword": "Zamenjaj geslo", | ||||
|     "PersonalInfo": "Moj profil", | ||||
|     "AreYouSureYouWantToCancelEditingWarningMessage": "Imate neshranjene spremembe.", | ||||
|     "UnhandledException": "Neobravnavana napaka!", | ||||
|     "401Message": "Nepooblaščeno", | ||||
|     "403Message": "Prepovedano", | ||||
|     "404Message": "Strani ni mogoče najti", | ||||
|     "500Message": "Napaka na strani strežnika", | ||||
|     "GoHomePage": "Pojdi na osnovno stran", | ||||
|     "GoBack": "Nazaj" | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,19 @@ | ||||
| @page | ||||
| @model Volo.Abp.AspNetCore.Mvc.Auditing.AuditTestPage | ||||
| 
 | ||||
| @{ | ||||
|     Layout = null; | ||||
| } | ||||
| 
 | ||||
| <!DOCTYPE html> | ||||
| 
 | ||||
| <html> | ||||
| <head> | ||||
|     <title></title> | ||||
| </head> | ||||
| <body> | ||||
| <div> | ||||
|      | ||||
| </div> | ||||
| </body> | ||||
| </html> | ||||
| @ -0,0 +1,19 @@ | ||||
| @page | ||||
| @model Volo.Abp.AspNetCore.Mvc.Authorization.AuthTestPage | ||||
| 
 | ||||
| @{ | ||||
|     Layout = null; | ||||
| } | ||||
| 
 | ||||
| <!DOCTYPE html> | ||||
| 
 | ||||
| <html> | ||||
| <head> | ||||
|     <title></title> | ||||
| </head> | ||||
| <body> | ||||
| <div> | ||||
|      | ||||
| </div> | ||||
| </body> | ||||
| </html> | ||||
| @ -0,0 +1,19 @@ | ||||
| @page | ||||
| @model Volo.Abp.AspNetCore.Mvc.ExceptionHandling.ExceptionTestPage | ||||
| 
 | ||||
| @{ | ||||
|     Layout = null; | ||||
| } | ||||
| 
 | ||||
| <!DOCTYPE html> | ||||
| 
 | ||||
| <html> | ||||
| <head> | ||||
|     <title></title> | ||||
| </head> | ||||
| <body> | ||||
| <div> | ||||
|      | ||||
| </div> | ||||
| </body> | ||||
| </html> | ||||
| @ -0,0 +1,19 @@ | ||||
| @page | ||||
| @model Volo.Abp.AspNetCore.Mvc.Features.FeatureTestPage | ||||
| 
 | ||||
| @{ | ||||
|     Layout = null; | ||||
| } | ||||
| 
 | ||||
| <!DOCTYPE html> | ||||
| 
 | ||||
| <html> | ||||
| <head> | ||||
|     <title></title> | ||||
| </head> | ||||
| <body> | ||||
| <div> | ||||
|      | ||||
| </div> | ||||
| </body> | ||||
| </html> | ||||
| @ -0,0 +1,19 @@ | ||||
| @page | ||||
| @model Volo.Abp.AspNetCore.Mvc.Uow.UnitOfWorkTestPage | ||||
| 
 | ||||
| @{ | ||||
|     Layout = null; | ||||
| } | ||||
| 
 | ||||
| <!DOCTYPE html> | ||||
| 
 | ||||
| <html> | ||||
| <head> | ||||
|     <title></title> | ||||
| </head> | ||||
| <body> | ||||
| <div> | ||||
|      | ||||
| </div> | ||||
| </body> | ||||
| </html> | ||||
Some files were not shown because too many files have changed in this diff Show More
					Loading…
					
					
				
		Reference in new issue
	
	 liangshiwei
						liangshiwei