Andrew Andrew - 28 days ago 12
C# Question

Save object with one-many relationship

I have a

Company
model and I want to update the
Company
record and save a list of phone numbers all at once. There is a 1-* relationship.

My ViewModel looks like:

public class CompanyRegisterViewModel
{
public int CompanyId { get; set; }

public int CompanyTypeId { get; set; }

public IEnumerable<SelectListItem> CompanyTypes { get; set; }

[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ValidationStringResource))]
[MaxLength(250, ErrorMessageResourceName = "MaximumLength", ErrorMessageResourceType = typeof(ValidationStringResource))]
public string LicensedCompanyName { get; set; }

public List<Phone> Phones { get; set; }
}


In my
Save(Company company)
method, if I call:

_context.Companies.Add(company);
_context.SaveChanges();


Will this save a new company record and save the
List<Phone> Phones
or do I need a transaction and call
SaveChanges()
again to save the
Phones
. I also need to set
CreatedBy
and
DateCreated
for each
Phone
record. Should I loop through the
Phone
records prior to saving and update each record in a
foreach
loop? I want this set automatically in the backend, not in the UI.

Answer

If you want to automatically set properties like Modified and ModifiedBy everytime you call SaveChanges or SaveChangesAsync, you have to do 2 things.

Create a base interface, from which all your entities inherit from

public interface IEntityRoot
{
    public DateTime Created { get; set; }
    public string CreatedBy { get; set; }
    public DateTime Modified { get; set; }
    public string ModifiedBy { get; set; }
}

Inherit all your entites from this interface:

  public class Company : IEntityRoot { ... }

With this, all entities which inherit from this interface will have the properties Created & CreatedBy. The last step is to create a small method, which is called every time you save your changes and automatically sets the current date and user.

public class ApplicationContext : DbContext
{
    /* ... */
    public override int SaveChanges()
    {
        TrackModifiedDates();
        return base.SaveChanges();
    }

    public override async Task<int> SaveChangesAsync()
    {
        TrackModifiedDates();
        return await base.SaveChangesAsync();
    }

    private void TrackModifiedDates()
    {
        var entities = ChangeTracker.Entries()
                                    .Where(x => x.Entity is IEntityRoot && (x.State == EntityState.Added) || (x.State == EntityState.Modified));
        //if anonymous access is possible, do a null check here.
        var userName = HttpContext.Current.User.Identity.Name

        foreach (var entity in entities)
        {
            if(entity.State == EntityState.Added) 
            {
                ((IEntityRoot)entity.Entity).Created = DateTime.UtcNow;
                ((IEntityRoot)entity.Entity).CreatedBy = userName;
            }  

            ((IEntityRoot)entity.Entity).Modified = DateTime.UtcNow;
            ((IEntityRoot)entity.Entity).ModifiedBy = userName;
        }
    }
}
Comments