I am currently having an issue with entity framework, when trying to updated my CaapListItem entity using the Exported() method only the first items status is being updated any after that get a NULL inserted. All other fields for that element are updated correctly. As shown below:
I have stepped through this code and can see that each caaplistitem gets assigned the correct status but then when entity framework runs the SaveChanges() it strips them out. I can see via sql profiler that the two elements are set to NULL. Is there a known bug in which Enumeration classes don't play well with EF?
CaapListItem Class
public class CaapListItem : Entity, IAggregateRoot, IDeletable
{
public Guid Guid { get; protected set; }
public int AgreementId { get; private set; }
public int UserId { get; private set; }
public CaapStatus? Status { get; private set; }
public DateTime DateAddedToReadyForExport { get; private set; }
public DateTime? DateExported { get; private set; }
public DateTime? DateImported { get; private set; }
public string? ExportFilePath { get; private set; }
public string? ImportFilename { get; private set; }
private bool _delete;
public bool Delete => _delete;
public CaapListItem(int agreementId, int userId)
{
Guid = Guid.NewGuid();
AgreementId = agreementId;
UserId = userId;
}
private CaapListItem() {
}
public void ReadyForExport()
{
this.Status = CaapStatus.ReadyForExport;
DateAddedToReadyForExport = DateTime.Now;
}
/// <summary>
/// Sets the item to exported
/// </summary>
public void Exported(string exportFilePath)
{
this.Status = CaapStatus.Exported;
this.DateExported = DateTime.Now;
this.ExportFilePath = exportFilePath;
this.AddDomainEvent(new CaapListItemExportedDomainEvent(AgreementId));
}
}
CaapStatus Enumeration Class
public class CaapStatus : Enumeration
{
public static readonly CaapStatus ReadyForExport = new(1, nameof(ReadyForExport));
public static readonly CaapStatus Exported = new(2, nameof(Exported));
public static readonly CaapStatus Imported = new(3, nameof(Imported));
private CaapStatus()
{
}
private CaapStatus(int id, string name)
: base(id, name)
{
}
}
Handler that calls export on each CaapListItem and saves all to database.
public async Task<AggregateRootGuid> Handle(CaapExportCommand request,
CancellationToken cancellationToken)
{
var agreements = await _context.Agreements.Include(a => a.Terminals)
.Where(t => request.AgreementIds.Contains(t.Guid)).ToArrayAsync()
?? throw new NullReferenceException($"No agreements with the Ids " +
$"{request.AgreementIds} could be found. Please check the agreements exist.");
var calledOffAgreements = Array.ConvertAll(agreements, item => (CalledOffAgreement)item);
//Export to csv
var caapResults = _caapExportService.GetCaapFieldsForExport(calledOffAgreements);
var exportFilePath = _caapExportService.ExportToCsv(caapResults);
foreach (var agreement in calledOffAgreements)
{
var caapListItem = await _context.CaapList
.FirstOrDefaultAsync(t => t.AgreementId! == agreement.Id) ??
throw new NullReferenceException("$No Caap List Item could be found with the" +
$"Id of {agreement.Id}. Please check the agreement exists and is in the caap export list.");
caapListItem.Exported(exportFilePath);
}
await _context.SaveChangesAsync(cancellationToken);
return new AggregateRootGuid(request.AgreementIds[0]);
}
EF type configuration
internal class EFCaapListItemConfig : IEntityTypeConfiguration<CaapListItem>
{
public void Configure(EntityTypeBuilder<CaapListItem> builder)
{
builder.ToTable("CaapList");
builder.OwnsOne(a => a.Status, status =>
{
status.Property(p => p.Id).HasColumnName("CaapStatusId");
status.Ignore(p => p.Name);
});
}
}