Home > database >  Update related entities data during adding data for an entity in EF Core
Update related entities data during adding data for an entity in EF Core

Time:08-08

I have two entities Payroll and Entries which have one to many relationship. Multiple entries can be associated to a payroll. Basically, during the newly payroll creation, entries needs to be associated with the PayrollId and for that I have wrote the below mentioned code to achieve the whole changes in single SaveChanges().

Payroll entity:

public class Payroll : BaseEntity, ITrackCreated, ITrackUpdated
{
    public int PayrollId { get; set; }
    public string Name { get; set; }
    public PayrollStatus Status { get; set; }
    public decimal Amount { get; set; }
    public List<Entries> Entries {get;set;}
}

Entries entity:

public class Entries : BaseEntity, ITrackCreated, ITrackUpdated
{
   public int EntryId { get; set; }
   public EntryType EntryType { get; set; }
   public DateTime EntryDate { get; set; }
   public Decimal Amount { get; set; }
   public EntryStatus Status { get; set; }
   public int? PayrollId { get; set; }
   public virtual Payroll Payroll {get;set;}
}

Entities relation:

public EntriesConfiguration(ModelBuilder modelBuilder) : base(modelBuilder)
{
    base.Configure();
    Builder.HasKey(t => t.EntryId);
    Builder.Property(p => p.EntryId).ValueGeneratedOnAdd();
    Builder.HasOne(x => x.Payroll).WithMany(x => x.Entries).HasForeignKey(x => x.PayrollId);
    Builder.ToTable("Entries");
}

Code for the payroll creation and payrollId update to entries:

foreach (var entryGroup in groups)
{
   var creditEntries = await _commonDbFunction.GetCreditEntries(entryGroup, EntryStatus.Pending);
   var debitEntries = await _commonDbFunction.GetDebitEntries(entryGroup, EntryStatus.Pending);
   exceptionPayrollDetail = CreatePayroll(payrollDetail); 
   // binding data in payroll entity model

   await _applicationDbContext.Payrolls.AddAsync(exceptionPayrollDetail);

   creditEntries?.ForEach(x => x.PayrollId = exceptionPayrollDetail?.PayrollId); 
   //updating payrollId of above model in Entries Table

   debitEntries?.ForEach(x => x.PayrollId = exceptionPayrollDetail?.PayrollId);
   //updating payrollId of above model in Entries Table

   await _applicationDbContext.SaveChangesAsync(); 
   // calling single SaveChanges adding payroll and updating enries.
}

Please suggest the way to achieve the same in single SaveChanges() as 0 PayrollId is not allowing to save the data in Entries table also payrollId should be greater than zero while updating in entries.

Thanks in advance..

CodePudding user response:

since the exceptionPayrollDetail is not yet persisted to the db, the exceptionPayrollDetail?.PayrollId will always be zero.

may be you can call SaveChangesAsync() after await _applicationDbContext.Payrolls.AddAsync(exceptionPayrollDetail);, then this would have the PayrollId generated

CodePudding user response:

You can set the navigation property itself, not the id, if you need.

Slightly simplified example:

public class ApplicationContext : DbContext
{
    public DbSet<Entries> Entries { get; set; }
    public DbSet<Payroll> Payrolls { get; set; }
    public string DbPath { get; }

    public ApplicationContext()
    {
        DbPath = System.IO.Path.Join(@"D:\Work\Envisability\EFCorePlayground\EFCorePlayground", "blogging.db");
    }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
    {
        options.UseSqlite($"Data Source={DbPath}");
        //options.LogTo(Console.WriteLine);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        var entriesBuilder = modelBuilder.Entity<Entries>();
        entriesBuilder.Property(p => p.EntryId).ValueGeneratedOnAdd();
        entriesBuilder.HasOne(x => x.Payroll).WithMany(x => x.Entries).HasForeignKey(x => x.PayrollId);
        entriesBuilder.HasKey(t => t.EntryId);
        entriesBuilder.ToTable("Entries");
    }

    public void Seed()
    {
        if (Entries.Any() || Payrolls.Any()) return;

        var entries = new List<Entries>
        {
            new Entries{ Name="e1" },
            new Entries{ Name="e2" },
            new Entries{ Name="e3" }
        };
        var payrolls = new List<Payroll>
        {
            new Payroll{ Name = "1" },
            new Payroll{ Name = "2" },
        };

        entries[0].Payroll = payrolls[0];
        entries[1].Payroll = payrolls[0];
        entries[2].Payroll = payrolls[1];

        Payrolls.AddRange(payrolls);
        Entries.AddRange(entries);
        SaveChanges();
    }

}

public class Payroll
{
    public int PayrollId { get; set; }
    public string Name { get; set; }
    public List<Entries> Entries { get; set; }
}

public class Entries
{
    public int EntryId { get; set; }
    public string Name { get; set; }
    public int? PayrollId { get; set; }
    public virtual Payroll Payroll { get; set; }
}

Take a look at the Seed method above, no ids there due to database is fresh and empty.

internal class Program
{
    static void Main(string[] args)
    {
        using (var _dbContext = new ApplicationContext())
        {
            _dbContext.Seed();

            var entries = _dbContext.Entries
                .Select(x => new {Id = x.EntryId, Name = x.Name, PayrollId = x.PayrollId})
                .ToList();
            var payrolls = _dbContext.Payrolls
                .Select(x => new {Id = x.PayrollId, Name = x.Name})
                .ToList();
            Debug.WriteLine(JsonSerializer.Serialize(entries));
            Debug.WriteLine(JsonSerializer.Serialize(payrolls));
        }
    }
}

Output will be

[
  {"Id":1,"Name":"e1","PayrollId":1},
  {"Id":2,"Name":"e2","PayrollId":1},
  {"Id":3,"Name":"e3","PayrollId":2}
]
[
  {"Id":1,"Name":"1"},{"Id":2,"Name":"2"}
]

Reference: https://docs.microsoft.com/en-us/ef/core/saving/related-data#adding-a-related-entity

  • Related