I'm currently making a web app using .net core 2.2 and EntityFramework.
I have a model which has 2 computed properties "AgeYears" and "AgeMonths" these properties are calculated based on the property "Birthday" by a class library.
When I run the web app, and there is a fetch which includes this model, an error is thrown:
System.InvalidOperationException: No backing field could be found for property 'AgeMonths' of entity type 'HorseModel' and the property does not have a setter.
I've tried to figure out what's going on by reading through a couple of articles one of which is on the Microsoft website but just returns a simple concatenation of FirstName and LastName (FullName) and the other didn't seem to be up to date as there were attributes that simply were not available e.g. [computed]. Usually, I wouldn't bother with the properties, and simply do the calculation in the view or page model, but stupidly thought this would be a better/cleaner idea!?
Here's the part of the model causing problems:
public DateTime Birthday { get; set; }
[NotMapped]
public int AgeYears
{
get
{
return DateTimeSpan.CompareDates(DateTime.Now, Birthday).Years;
}
}
[NotMapped]
public int AgeMonths
{
get
{
return DateTimeSpan.CompareDates(DateTime.Now, Birthday).Months;
}
}
I tried deleting the database and migrations, and upon attempting to run the initial migration again the error showed up, despite adding [NotMapped] to the properties.
What I was expecting to happen, is that when a record is fetched from the database, these properties are calculated and thought there would be no need to store them in the database. Clearly, I'm doing something wrong, and I assume its related to using my own functions for the calculation.
To make it work I've added a backing field as the error suggested I do, and when I look at the migration, I notice there are still columns being generated for the "NotMapped" values.
migrationBuilder.CreateTable(
name: "Horses",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Name = table.Column<string>(nullable: true),
Birthday = table.Column<DateTime>(nullable: false),
AgeYears = table.Column<int>(nullable: false),
AgeMonths = table.Column<int>(nullable: false),
Breed = table.Column<string>(nullable: true),
Height = table.Column<decimal>(nullable: false),
About = table.Column<string>(nullable: true),
ForSale = table.Column<bool>(nullable: false),
Private = table.Column<bool>(nullable: false),
OwnerId = table.Column<string>(nullable: true),
Created = table.Column<DateTime>(nullable: false),
LastEdited = table.Column<DateTime>(nullable: false),
PurhaseDate = table.Column<DateTime>(nullable: false),
Sold = table.Column<DateTime>(nullable: false),
Slug = table.Column<string>(nullable: true),
OwnershipStatus = table.Column<int>(nullable: false)
},...
Now however AgeYears and AgeMonths don't get calculated when they are fetched!
The final model that I came up with is:
public class HorseModel
{
private int _ageYears;
private int _ageMonths;
public int Id { get; set; }
public string Name { get; set; }
public DateTime Birthday { get; set; }
[NotMapped]
public int AgeYears
{
get
{
return _ageYears;
}
set
{
_ageYears = DateTimeSpan.CompareDates(DateTime.Now, Birthday).Years;
}
}
[NotMapped]
public int AgeMonths
{
get
{
return _ageMonths;
}
set
{
_ageMonths = DateTimeSpan.CompareDates(DateTime.Now, Birthday).Months;
}
}
public string Breed { get; set; }
public decimal Height { get; set; }
public string About { get; set; }
public bool ForSale { get; set; }
public bool Private { get; set; }
[ForeignKey("Owner")]
public string OwnerId { get; set; }
public ApplicationUser Owner { get; set; }
public List<HorsePicture> Pictures { get; set; }
public List<HorseYouTubeVideo> Videos { get; set; }
public DateTime Created { get; set; }
public DateTime LastEdited { get; set; }
public DateTime PurhaseDate { get; set; }
public DateTime Sold { get; set; }
public HorseProfilePicture ProfilePicture { get; set; }
public string Slug { get; set; }
public OwnershipStatus OwnershipStatus { get; set; }
}
Any guidance would be very much appreciated.
Thanks :)