Rob Bowman
Rob Bowman

Reputation: 8711

EF Insert with relationships

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

Answers (2)

Marthijn
Marthijn

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

danludwig
danludwig

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

Related Questions