Reputation: 8711
I'm creating an MVC 5 website to track results of golf tournaments. I have 3 key tables, Event has many Results. Golfer has many Results. So for any row in the Result table I can link to the golfer and event.
I am using EF6 code first to persist to SQL Server.
Here's my poco for Event:
public class Event
{
public int EventId { get; set; }
public string VenueName { get; set; }
public string CourseName { get; set; }
public String FirstTeeOff { get; set; }
public DateTime EventDate { get; set; }
public decimal Fee { get; set; }
public virtual ICollection<Result> Results { get; set; }
}
And for Golfer:
public class Golfer
{
public int GolferId { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public int CurrentHandicap { get; set; }
public string Email { get; set; }
public string Telephone { get; set; }
public virtual ICollection<Result> Results { get; set; }
}
And for Result:
public class Result
{
public int ResultId { get; set; }
public Golfer Golfer { get; set; }
public Event Event { get; set; }
public bool Attendance { get; set; }
public int HandicapPlayed { get; set; }
public int ScoreCarded { get; set; }
public Result()
{
Event = new Event();
Golfer = new Golfer();
}
}
Here's my model context:
public class ModelContext : IdentityDbContext<ApplicationUser>, SANDGolf.DataLayer.IModelContext
{
public ModelContext() : base("ModelContextConString") { }
public virtual DbSet<SANDGolf.DomainClasses.Golfer> Golfers { get; set; }
public virtual DbSet<SANDGolf.DomainClasses.Event> Events { get; set; }
public virtual DbSet<SANDGolf.DomainClasses.Result> Results { get; set; }
}
I am using the following controller action to try to insert into the result table to record attendance.
[HttpPost]
[Authorize]
public ActionResult ExpectedAttendance(ExpectedAttendanceViewModel eaVM)
{
try
{
foreach(GolferAttendanceViewModel gaVM in eaVM.GolferAttendanceViewModel)
{
DomainClasses.Result resultDomain = new DomainClasses.Result();
resultDomain.Attendance = gaVM.Attending;
resultDomain.Event.EventId = eaVM.Event.EventId;
resultDomain.Golfer.GolferId = gaVM.Golfer.GolferId;
_context.Entry(resultDomain).State = EntityState.Modified;
_context.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
When the line _context.SaveChanges(); executes I get the following error:
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
I am new to EF so would be grateful if anyone could let me know where I'm going wrong.
Upvotes: 0
Views: 110
Reputation: 3392
I suggest to switch to foreign key associations. For example:
public virtual Golfer Golfer {get;set;}
will become:
public int GolferId {get;set;}
public virtual Golfer Golfer {get;set;}
Using this approach you can just set for example:
Golfer myGolfer = getGolferById(1); // or gaVM.Golfer.GolverId;
Result.GolferId = myGolfer.GolferId;
You can read more about this on my blog.
And when adding a new entity to the database you should not use:
_context.Entry(resultDomain).State = EntityState.Modified;
but use @danludwig's solution.
Upvotes: 1
Reputation: 47375
Navigation properties also need to be virtual.
public virtual Golfer Golfer { get; set; }
public virtual Event Event { get; set; }
Also, like Scott Corbett said, your new entity should not have modified state, but rather added state:
_context.Entry(resultDomain).State = EntityState.Added;
... or better yet:
_context.Results.Add(resultDomain);
Upvotes: 1