0

I am trying to update an entity and all of it's relationships and I'm not sure if that's possible. If it isn't possible, what's the best way of going about it?

My ASP MVC Controller...

public ActionResult TimeSheetEdit(Timesheet timesheet, string submitType)
{
    _timesheetRepository.Update(timesheet);
    _timesheetRepository.Commit();

    return RedirectToAction("TimeSheetEdit", new {id=timesheet.TimeSheetId});
}

My timesheet Model has multiple properties, one property is another entity (which has a list of entities). I was hoping EF would go map through all of my relationships and update everything, but it appears that it only updates the Timesheet model and ignores all the other associated entities.

Is this normal or am I missing something? If it's normal, what's the best practice for accomplishing what I'm trying to do?

Repository Update code...

    public void Update(T entity)
    {
        _dbSet.Attach(entity);
        _context.Entry(entity).State = EntityState.Modified;
    }

    public int Commit()
    {
        return _context.SaveChanges();
    }

I'm not sure if it will help, but here are my Models

Timesheet

public class Timesheet
    {
        [Key]
        public int TimeSheetId { get; set; }

        public Guid Id { get; set; }

        public DateTime StartDate { get; set; }

        public DateTime EndDate { get; set; }

        public TimeSheetStatus TimeSheetStatus { get; set; }

        public int EmployeeId { get; set; }

        public virtual Employee Employee { get; set; }

        public virtual List<TimesheetLine> TimesheetLines { get; set; }
    }  

TimesheetLine

public class TimesheetLine
{
    [Key]
    public int TimeSheetLineId { get; set; }

    public Guid CustomerId { get; set; }

    public string CustomerName { get; set; }

    public Guid EarningsId { get; set; }

    public virtual List<TimeSheetLineUnit> Units  { get; set; }

    public int TimeSheetId { get; set; }

    public virtual Timesheet Timesheet { get; set; }
}

TimeSheetLineUnit

public class TimeSheetLineUnit
{
    [Key]
    public int UnitId { get; set; }

    public decimal Hours { get; set; }

    [DisplayName("Notes")]
    public string Description { get; set; }

    public int Index { get; set; }

    public int TimeSheetLineId { get; set; }

    public virtual TimesheetLine TimesheetLine { get; set; }

}
Safari137
  • 336
  • 3
  • 9
  • Put a breakpoint in yout ActionResult and see whether your property(of type another entity) has the updated value. – Shyju Jan 11 '16 at 00:19
  • I did do that. I can see the updated value of all properties in the Controller and Update method after submitting my form. – Safari137 Jan 11 '16 at 00:29
  • One thing about MVC is that it uses the 'name' attribute to process/send data back to the server. Each name in your list of child records needs to be unique. – Gwasshoppa Jan 11 '16 at 02:35

3 Answers3

0

To try to explain my comment above here is what I suggest may be the issue.

MVC required the 'Name" attribute to be unique when returning data base as a model to the server.

I would loop through the child records something like so:

@for (int i = 0; i < Model.Count; i++)
      {
        <tr>
          <td style="text-align: center;" class="Cell">
            @Html.CheckBoxFor(m => Model[i].Selected)
          </td>
          <td class="Cell">
            @Html.DisplayFor(m => Model[i].Name)
            @Html.HiddenFor(m => Model[i].Name)
          </td>
          <td class="Cell">
            @Html.DisplayFor(m => Model[i].AddressPhysical)
            @Html.HiddenFor(m => Model[i].AddressPhysical)
          </td>
          <td class="Cell">
            @Html.DisplayFor(m => Model[i].AddressPhysicalPostCode)
            @Html.HiddenFor(m => Model[i].AddressPhysicalPostCode)
          </td>
        </tr>
      }

Note: If you do this each child row in the list will have its own unique 'Name' attribute, and MVC will be able to uniquely identify each row of data, and therefore the full data will be correctly passed back to the server within the model.

This is a sample only but try this an see how you go.

Gwasshoppa
  • 864
  • 11
  • 18
  • Thanks for the answer. My View is very similar to this. I'm not having any trouble getting the correct data from my view to my Controller or to my Repository. Something in my Repository isn't working as I was expecting it. – Safari137 Jan 11 '16 at 02:53
  • Ahhh ok... Sorry didn't realise that... Have you checked the Mappings in Entity Framework to ensure you are not missing any relationships, and also the database relationships correspond to these mappings? The most common mistake I make is not putting in the mapping record. – Gwasshoppa Jan 11 '16 at 03:10
0

for Ef update repository don't use attach first inject you DbContext in construct in your generic repository

  // my generic repository
  public class EntityBaseRepository<T>:IEntityBaseRepository<T> 
   where T :class , new()
 {
    //my context
    private DataContext dbContext;

     // use Dependency injection 
      public EntityBaseRepository(DataContext _dbContext)
   {
      this.dbContext = _dbContext;

   }


     //update method
       public void Update(T entity)
    {
        DbEntityEntry entry = this.dbContext.Entry(entity);
        entry.State = EntityState.Modified;
    }


 }

 // at the end call DbContext SaveChanges() from controller
Hisham
  • 1,105
  • 1
  • 16
  • 22
-1

Please check this:

Maybe You need to add some codes at the update way.

Something like this:

public void Update(Timesheet timesheet)
{
    var existingParent = _dbContext.Parents
        .Where(p => p.Id == timesheet.Id)
        .Include(p => p.TimesheetLines)
        .SingleOrDefault();

    if (existingParent != null)
    {
        // Update parent
        _dbContext.Entry(existingParent).CurrentValues.SetValues(timesheet);

        // Delete TimesheetLines
        foreach (var existingChild in existingParent.TimesheetLines.ToList())
        {
            if (!timesheet.TimesheetLines.Any(c => c.Id == existingChild.Id))
                _dbContext.TimesheetLines.Remove(existingChild);
        }

        // Update and Insert TimesheetLines
        foreach (var childtimesheet in timesheet.TimesheetLines)
        {
            var existingChild = existingParent.TimesheetLines
                .Where(c => c.Id == childtimesheet.Id)
                .SingleOrDefault();

            if (existingChild != null)
                // Update child
                _dbContext.Entry(existingChild).CurrentValues.SetValues(childtimesheet);
            else
            {
                // Insert child
                var newChild = new Child
                {
                    Data = childtimesheet.Data,
                    //...
                };
                existingParent.TimesheetLines.Add(newChild);
            }
        }

        _dbContext.SaveChanges();
    }
}
Community
  • 1
  • 1
toha
  • 4,643
  • 3
  • 35
  • 52