对象扩展

    这是一个使类可扩展的接口. 它定义了 属性:

    然后你可以使用此字典添加或获取其他属性.

    默认以下基类实现了 IHasExtraProperties 接口:

    • AggregateRoot 类实现 (参阅 ).
    • ExtensibleEntityDto, ExtensibleAuditedEntityDtoDTO基类实现.
    • ExtensibleObject 实现, 它是一个简单的基类,任何类型的对象都可以继承.

    如果你的类从这些类继承,那么你的类也是可扩展的,如果没有,你也可以随时手动继承.

    基本扩展方法

    虽然可以直接使用类的 ExtraProperties 属性,但建议使用以下扩展方法使用额外属性.

    SetProperty

    用于设置额外属性值:

    1. user.SetProperty("Title", "My Title");
    2. user.SetProperty("IsSuperUser", true);

    SetProperty 返回相同的对象, 你可以使用链式编程:

    1. user.SetProperty("Title", "My Title")
    2. .SetProperty("IsSuperUser", true);

    GetProperty

    用于读取额外属性的值:

    1. var title = user.GetProperty<string>("Title");
    2. if (user.GetProperty<bool>("IsSuperUser"))
    3. {
    4. //...
    5. }
    • GetProperty 是一个泛型方法,对象类型做为泛型参数.
    • 如果未设置给定的属性,则返回默认值 (int 的默认值为 0 , bool 的默认值是 false … 等).
    非基本属性类型

    如果你的属性类型不是原始类型(int,bool,枚举,字符串等),你需要使用 GetProperty 的非泛型版本,它会返回 object.

    HasProperty

    用于检查对象之前是否设置了属性.

    RemoveProperty

    用于从对象中删除属性. 使用此方法代替为属性设置 null 值.

    为属性名称使用魔术字符串很危险,因为你很容易输入错误的属性名称-这并不安全;

    • 为你的额外属性名称定义一个常量.
    • 使用扩展方法轻松设置你的属性.

    示例:

    1. public static class IdentityUserExtensions
    2. {
    3. private const string TitlePropertyName = "Title";
    4. public static void SetTitle(this IdentityUser user, string title)
    5. {
    6. user.SetProperty(TitlePropertyName, title);
    7. }
    8. public static string GetTitle(this IdentityUser user)
    9. {
    10. }
    11. }

    然后, 你可以很容易地设置或获取 Title 属性:

    1. user.SetTitle("My Title");
    2. var title = user.GetTitle();

    你可以为可扩展对象(实现 IHasExtraProperties接口)设置任意属性, ObjectExtensionManager 用于显式定义可扩展类的其他属性.

    显式定义额外的属性有一些用例:

    • 允许控制如何在对象到对象的映射上处理额外的属性 (参阅下面的部分).
    • 允许定义属性的元数据. 例如你可以在使用时将额外的属性映射到数据库中的表字段.

    AddOrUpdate

    AddOrUpdate 是定义对象额外属性或更新对象额外属性的主要方法.

    示例: 为 IdentityUser 实体定义额外属性:

    1. ObjectExtensionManager.Instance
    2. .AddOrUpdate<IdentityUser>(options =>
    3. {
    4. options.AddOrUpdateProperty<string>("SocialSecurityNumber");
    5. options.AddOrUpdateProperty<bool>("IsSuperUser");
    6. }
    7. );

    虽然可以如上所示使用 AddOrUpdateProperty, 但如果要定义单个额外的属性,也可以使用快捷的扩展方法:

    有时将单个额外属性定义为多种类型是可行的. 你可以使用以下代码,而不是一个一个地定义:

    1. ObjectExtensionManager.Instance
    2. .AddOrUpdateProperty<string>(
    3. new[]
    4. {
    5. typeof(IdentityUserDto),
    6. typeof(IdentityUserUpdateDto)
    7. },
    8. "SocialSecurityNumber"
    9. );

    属性配置

    AddOrUpdateProperty 还可以为属性定义执行其他配置的操作.

    Example:

    1. ObjectExtensionManager.Instance
    2. .AddOrUpdateProperty<IdentityUser, string>(
    3. "SocialSecurityNumber",
    4. options =>
    5. {
    6. options.CheckPairDefinitionOnMapping = false;
    7. });

    options 有一个名为 Configuration 的字典,该字典存储对象扩展定义甚至可以扩展. EF Core使用它来将其他属性映射到数据库中的表字段. 请参阅扩展实体文档.

    默认值

    自动为新属性设置默认值,默认值是属性类型的自然默认值,例如: string: null , bool: falseint: 0.

    有两种方法可以覆盖默认值:

    DefaultValue 选项

    DefaultValue 选项可以设置任何值:

    1. ObjectExtensionManager.Instance
    2. .AddOrUpdateProperty<IdentityUser, int>(
    3. "MyIntProperty",
    4. options =>
    5. {
    6. options.DefaultValue = 42;
    7. });
    DefaultValueFactory 选项

    DefaultValueFactory 可以设置返回默认值的函数:

    1. ObjectExtensionManager.Instance
    2. .AddOrUpdateProperty<IdentityUser, DateTime>(
    3. "MyDateTimeProperty",
    4. options =>
    5. {
    6. options.DefaultValueFactory = () => DateTime.Now;
    7. });

    options.DefaultValueFactoryoptions.DefaultValue 优先级要高.

    CheckPairDefinitionOnMapping

    控制在映射两个可扩展对象时如何检查属性定义. 请参阅对象到对象映射部分,了解 CheckPairDefinitionOnMapping 选项.

    你可能要为你定义的额外属性添加一些 验证规则. AddOrUpdateProperty 方法选项允许进行验证的方法有两种:

    1. 你可以为属性添加 数据注解 attributes.
    2. 你可以给定一个action(代码块)执行 自定义验证.

    当你在自动验证的方法(例如:控制器操作,页面处理程序方法,应用程序服务方法…)中使用对象时,验证会工作. 因此,每当扩展对象被验证时,所有额外的属性都会被验证.

    数据注解 Attributes

    1. ObjectExtensionManager.Instance
    2. .AddOrUpdateProperty<IdentityUserCreateDto, string>(
    3. "SocialSecurityNumber",
    4. options =>
    5. {
    6. options.Attributes.Add(new RequiredAttribute());
    7. options.Attributes.Add(
    8. new StringLengthAttribute(32) {
    9. }
    10. );
    11. });

    使用以上配置,如果没有提供有效的 SocialSecurityNumber 值, IdentityUserCreateDto 对象将是无效的.

    如果需要,可以添加一个自定义action验证额外属性. 例:

    1. ObjectExtensionManager.Instance
    2. .AddOrUpdateProperty<IdentityUserCreateDto, string>(
    3. "SocialSecurityNumber",
    4. {
    5. options.Validators.Add(context =>
    6. {
    7. var socialSecurityNumber = context.Value as string;
    8. if (socialSecurityNumber == null ||
    9. socialSecurityNumber.StartsWith("X"))
    10. {
    11. context.ValidationErrors.Add(
    12. new ValidationResult(
    13. "Invalid social security number: " + socialSecurityNumber,
    14. new[] { "SocialSecurityNumber" }
    15. )
    16. );
    17. }
    18. });
    19. });

    context.ServiceProvider 可以解析服务.

    除了为单个属性添加自定义验证逻辑外,还可以添加在对象级执行的自定义验证逻辑. 例:

    假设你已向可扩展的实体对象添加了额外的属性并使用了自动将该实体映射到可扩展的DTO类. 在这种情况下你需要格外小心,因为额外属性可能包含敏感数据,这些数据对于客户端不可用.

    本节提供了一些好的做法,可以控制对象映射的额外属性.

    MapExtraPropertiesTo

    MapExtraPropertiesTo 是ABP框架提供的扩展方法,用于以受控方式将额外的属性从一个对象复制到另一个对象. 示例:

    1. identityUser.MapExtraPropertiesTo(identityUserDto);

    MapExtraPropertiesTo 需要在两侧(本例中是IdentityUserIdentityUserDto)定义属性. 以将值复制到目标对象. 否则即使源对象(在此示例中为 identityUser )中确实存在该值,它也不会复制. 有一些重载此限制的方法.

    MappingPropertyDefinitionChecks

    MapExtraPropertiesTo 获取一个附加参数来控制单个映射操作的定义检查:

    1. identityUser.MapExtraPropertiesTo(
    2. identityUserDto,
    3. MappingPropertyDefinitionChecks.None
    4. );

    如果要完全禁用属性的定义检查,可以在定义额外的属性(或更新现有定义)时进行,如下所示:

    1. ObjectExtensionManager.Instance
    2. .AddOrUpdateProperty<IdentityUser, string>(
    3. "SocialSecurityNumber",
    4. options =>
    5. {
    6. options.CheckPairDefinitionOnMapping = false;
    7. });

    忽略属性

    你可能要在映射操作忽略某些属性:

    1. identityUser.MapExtraPropertiesTo(
    2. identityUserDto,
    3. ignoredProperties: new[] {"MySensitiveProp"}
    4. );

    忽略的属性不会复制到目标对象.

    AutoMapper集成

    如果你使用的是AutoMapper库,ABP框架还提供了一种扩展方法来利用上面定义的 MapExtraPropertiesTo 方法.

    你可以在映射配置文件中使用 MapExtraProperties() 方法.

    1. public class MyProfile : Profile
    2. {
    3. public MyProfile()
    4. {
    5. CreateMap<IdentityUser, IdentityUserDto>()
    6. .MapExtraProperties();
    7. }
    8. }

    它与 MapExtraPropertiesTo() 方法具有相同的参数.

    如果你使用的是EF Core,可以将额外的属性映射到数据库中的表字段. 例:

    1. ObjectExtensionManager.Instance
    2. .AddOrUpdateProperty<IdentityUser, string>(
    3. "SocialSecurityNumber",
    4. options =>
    5. {
    6. options.MapEfCore(b => b.HasMaxLength(32));
    7. );