【问题标题】:Validate a Create and Edit DTO with nealy all same properties验证具有几乎所有相同属性的创建和编辑 DTO
【发布时间】:2015-06-29 07:42:26
【问题描述】:

我的 DTO 太相似了。

它们的区别仅在于标识测试资源的一个属性。

当我现在创建一个 EditAddTestDTO 并制作

public int<Nullable> TestId {get;set;}

然后我不能把 RequireAttribute 放在它上面,因为它在我显然没有 TestId 的 Create-Scenario 中不起作用。

你如何解决这个问题?

创建 2 个我已有的 DTO 或 AddEditBaseDTO?

public class EditTestDTO
{        
    [Required]
    public DateTime Date { get; set; }
    [Required]
    public int Number { get; set; }
    [Required]
    public int SchoolclassCodeId { get; set; }
    [Required]
    public int SchoolyearId { get; set; }
    [Required]
    public int TestTypeId { get; set; }
    [Required]
    public int TestId { get; set; }
}

public class CreateTestDTO
{
    [Required]
    public DateTime Date { get; set; }
    [Required]
    public int Number { get; set; }
    [Required]
    public int SchoolclassCodeId { get; set; }
    [Required]
    public int SchoolyearId { get; set; }
    [Required]
    public int TestTypeId { get; set; }
}

【问题讨论】:

  • 首先——为什么要创建一个需要的可为空的属性?
  • 因为...“那我不能把 RequireAttribute 放在它上面,因为它在我没有 TestId 的 Create-Scenario 中不起作用。”

标签: c# asp.net-web-api dto data-transfer-objects


【解决方案1】:

我会避免共享基类。您没有尝试在类之间共享逻辑,因此请保持它们简洁明了。

如果您想为两个模型使用一些相同的代码,请改为添加一个接口并让两个类实现它。这样做的好处是,可以在不同的项目中使用任何使用它的服务来定义接口。

编辑:

假设您只需要在您的服务中读取访问权限,您可能会有这样的事情,但这实际上取决于您需要访问哪些属性:

public interface ITestDTO
{
    DateTime Date { get; }
    int Number { get; }
    int SchoolClassCodeId { get; }
    int SchoolYearId { get; }
    int TestTypeId { get; }
    int? TestId { get; }
}

public class EditTestDTO : ITestDTO
{
    [Required]
    public DateTime Date { get; set; }
    [Required]
    public int Number { get; set; }
    [Required]
    public int SchoolClassCodeId { get; set; }
    [Required]
    public int SchoolYearId { get; set; }
    [Required]
    public int TestTypeId { get; set; }
    [Required]
    public int TestId { get; set; }

    int? ITestDTO.TestId { get { return TestId; } }
}

public class CreateTestDTO : ITestDTO
{
    [Required]
    public DateTime Date { get; set; }
    [Required]
    public int Number { get; set; }
    [Required]
    public int SchoolClassCodeId { get; set; }
    [Required]
    public int SchoolYearId { get; set; }
    [Required]
    public int TestTypeId { get; set; }

    int? ITestDTO.TestId { get { return null; } }
}

可为空的 TestId 允许您区分服务中的编辑和创建。

【讨论】:

  • 界面会是什么样子? 5个属性?开销很大?
  • 感谢您的示例,但我不会使用它,因为它的开销太大。属性通常没有逻辑和隐含。因为接口也是空的。我坚持 KISS ;-)
【解决方案2】:

您可以创建一个包含所有必要属性的抽象类TestDTO(但我相信我编辑的答案比创建所有这些抽象的东西更好):

public abstract class TestDTO
{

   public abstract DateTime Date { get; set; }

   public abstract int Number { get; set; }

   public abstract int SchoolclassCodeId { get; set; }

   public abstract int SchoolyearId { get; set; }

   public abstract int TestTypeId { get; set; }
}

然后只需在您的其他 DTO 中实现属性,或者将这些属性放在您的 CreateTestDTO 中,然后从它派生到 EditTestDTO 添加 TestId 属性。

编辑:

那么你可以有以下类:

public class CreateTestDTO : TestDTO
{
   [Required]
   public DateTime Date { get; set; }
   [Required]
   public int Number { get; set; }
   [Required]
   public int SchoolclassCodeId { get; set; }
   [Required]
   public int SchoolyearId { get; set; }
   [Required]
   public int TestTypeId { get; set; }

}

public class EditTestDTO : TestDTO
{        
   [Required]
   public DateTime Date { get; set; }
   [Required]
   public int Number { get; set; }
   [Required]
   public int SchoolclassCodeId { get; set; }
   [Required]
   public int SchoolyearId { get; set; }
   [Required]
   public int TestTypeId { get; set; }
   [Required]
   public int TestId { get; set; }

}

另一种方法是使用IValidatableObject 接口验证您的模型并添加一个可在验证期间使用的标志:

public class EditTestDTO : IValidatableObject
{        
   [Required]
   public DateTime Date { get; set; }
   [Required]
   public int Number { get; set; }
   [Required]
   public int SchoolclassCodeId { get; set; }
   [Required]
   public int SchoolyearId { get; set; }
   [Required]
   public int TestTypeId { get; set; }

   public int? TestId { get; set; }

   public bool IsEdit {get;set;}

   public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
   {
      if(IsEdit) 
      {
          if(!TestId.HasValue)
          {
              yield return new ValidationResult();
          }
      }
   }
}

【讨论】:

  • 这将是子类和基类之间的强耦合。如果我必须在 EditTestDTO 中放置一个不能在 CreateTestDTO 中存在的属性怎么办?那我就完蛋了……
  • @Elisa - 不,你误解了我的意思。在这种情况下,您创建TestDTO 并在CreateTestDTOEditTestDTO 中从它派生。它使您可以在两个 DTO 中添加您喜欢的任何内容,而不会相互影响。我相信对于这种特殊情况有一些奇特的模式 - 这完全取决于您希望看到的结果。
  • 但是我的 CreateTestDTO 将是空的,只有基本属性。派生没有内容的东西没有意义?!
  • @Elisa - “没有内容”是什么意思?根据定义,DTO 没有真正的内容。由于所有这些属性都是抽象的,因此您必须在两个 DTO 以及数据注释中实现它们。
  • 好吧,说这么多...我们都感到困惑 ;-) 您能否像使用基本 TestDTO 一样为 EditTestDTO 和 CreateTestDTO 添加一个代码 sn-p 来查看并向您展示我的请问有什么问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多