我正在研究动物收容所。员工需要能够将新动物添加到数据库中。动物具有三个属性:出生日期,年龄和估计年龄。用户可以输入“出生日期”字段和“估计年龄”字段。
如果两个字段都具有值,我想抛出一个异常。如果它们都没有值,我也想抛出一个异常。如果输入生日,将计算年龄,并将年龄属性设置为计算值。如果输入了估计年龄,则年龄值将设置为估计年龄。
我似乎无法在我的域类中找到正确的处理方式。目前,如果同时输入了估计的年龄和出生日期,则不会抛出异常并将动物添加到数据库中。
动物领域类:
public class Animal
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime? Birthdate { get; set; }
private int _age;
public int Age
{
get
{
return _age;
}
set
{
if (EstimatedAge.HasValue && Birthdate.HasValue)
{
throw new InvalidOperationException();
}
else if (!EstimatedAge.HasValue && !Birthdate.HasValue)
{
throw new InvalidOperationException();
}
else if (EstimatedAge.HasValue && !Birthdate.HasValue)
{
_age = (int) EstimatedAge;
}
else
{
_age = CalculateAge(Birthdate);
}
}
}
public int? EstimatedAge { get; set; }
public string Description { get; set; }
public AnimalType Type { get; set; }
public string Breed { get; set; }
public Gender Gender { get; set; }
public string Photo { get; set; }
public DateTime ArrivalDate { get; set; }
public DateTime? AdoptionDate { get; set; }
public DateTime? DeathDate { get; set; }
public bool SterilizedOrCastrated { get; set; }
public bool? ChildFriendly { get; set; }
public string Reason { get; set; }
public bool Adoptable { get; set; } = true;
public string AdoptedBy { get; set; }
public Residence Residence { get; set; }
public int ResidenceId { get; set; }
public ICollection<Treatment> Treatments { get; set; }
public ICollection<Comment> Comments { get; set; }
// Calculates the animal's age based on the entered birthdate.
public int CalculateAge(DateTime? birthdate)
{
// Save today's date.
var today = DateTime.Today;
// Calculate the age.
var age = today.Year - birthdate?.Year;
// Go back to the year in which the person was born in case of a leap year.
if (birthdate?.Date > today.AddYears((int) -age))
{
age--;
}
return (int) age;
}
创建动物的控制器中的操作方法:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> NewAnimal(NewAnimalViewModel newAnimal)
{
var animalToCreate = new Animal()
{
Name = newAnimal.Name,
Birthdate = newAnimal.Birthdate,
Age = newAnimal.Age,
EstimatedAge = newAnimal.EstimatedAge,
Description = newAnimal.Description,
Type = newAnimal.Type,
Breed = newAnimal.Breed,
Gender = newAnimal.Gender,
Photo = newAnimal.Photo,
ArrivalDate = newAnimal.ArrivalDate,
SterilizedOrCastrated = newAnimal.SterilizedOrCastrated,
ChildFriendly = newAnimal.ChildFriendly,
Reason = newAnimal.Reason,
Adoptable = newAnimal.Adoptable,
Residence = newAnimal.Residence,
ResidenceId = newAnimal.ResidenceId
};
if (ModelState.IsValid)
{
await _animalRepository.AddAnimal(animalToCreate);
return RedirectToAction("Index");
}
PrefillSelectOptions();
return View(newAnimal);
}
答案 0 :(得分:1)
问题在于您正在使用字段初始化,并且它们是按如下顺序设置的:
var animal = new Animal();
animal.Birthdate = newAnimal.Birthdate;
animal.Age = newAnimal.Age;
animal.EstimatedAge = newAnimal.EstimatedAge;
结果是,当您设置字段Age时,您尚未设置EstimatedAge。因此,不会触发“年龄设置器”中的验证。
重新排序这些字段的初始化方式将触发验证。但是,验证依赖于初始化的顺序显然不好。您可以在Animal中添加“ IsValid()”方法,但正如@Jamiec所建议的那样,您可能应该在验证NewAnimalViewModel。
答案 1 :(得分:0)
尝试一下。创建一个专用方法来验证输入,并从属性Birthdate
和EstimatedAge
的设置器中调用它。如果满足条件,则引发异常。在您的代码中,仅当设置了Age
时才发生验证,并且您说用户仅输入Birthdate
和EstimatedAge
。
答案 2 :(得分:0)
您应该在模型上实现IValidatableObject
,然后实现Validate()
方法。这是模型级验证的模式,其中“此字段必须大于这两个字段的总和”,或其他多属性验证。
请参阅:
https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-2.2
在您的情况下,您的验证可能类似于:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Birthdate.HasValue && Age > 0)
yield return new ValidationResult($"Can't enter both.", new[] { "Birthdate" });
}
然后在您的控制器中,检查Model.IsValid