0

I am working with Entity Framework (code first) for the first time and I have a little problem.

I have a class called Taxi & one called Driver

Taxi has a reference to the Driver, you can see both classed below

  public partial class Taxi
    {
        public Taxi()
        {
        }

        public int TaxiId { get; set; }
        public Driver Driver { get; set; }
        public string Make { get; set; }
        public string Model { get; set; }
        public Color Colour { get; set; }
        public string NumPlate { get; set; }
        public int MaxPassengers { get; set; }
}


    public partial class Driver
    {
        public Driver()
        {

        }

        public int DriverId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Address { get; set; }
        public string HomePhone { get; set; }
        public string MobilePhone { get; set; }
        public DateTime JoinedFirm { get; set; }
}

And I am saving the changed Taxi like this:

 using (var db = new DataModel())
        {
            db.Configuration.ProxyCreationEnabled = false;

            db.Taxis
                .Where(x => x.TaxiId == CurrenltySelectedTaxi.TaxiId)
                .ToList()
                .ForEach(x =>
                {
                    x.Make = CurrenltySelectedTaxi.Make;
                    x.Model = CurrenltySelectedTaxi.Model;
                    x.NumPlate = CurrenltySelectedTaxi.NumPlate;
                    x.Colour = CurrenltySelectedTaxi.Colour;
                    x.MaxPassengers = CurrenltySelectedTaxi.MaxPassengers;
                    x.Driver = CurrenltySelectedTaxi.Driver;
                });

            db.SaveChanges();
        }

My problem is that the Driver gets duplicated the in database every time I save a taxi.

You can see the database here: enter image description here

Can someone point me in the right direction, Thanks

EDIT: The drivers are in a combo box and are selected like this

private void cmbTaxiDriver_SelectedIndexChanged(object sender, EventArgs e)
{
    using (var db = new DataModel())
    {
        db.Configuration.ProxyCreationEnabled = false;
        Driver listSelected = (Driver) cmbTaxiDriver.SelectedItem;
        CurrenltySelectedTaxi.Driver = db.Drivers.Where(x => x.DriverId == listSelected.DriverId).ToArray()[0];
    }
}

And the combo box is populated like this:

        listDrivers.Items.AddRange(db.Drivers.ToArray());
5
  • please include additional code, like how CurrenltySelectedTaxi is selected. Commented Jun 22, 2015 at 15:03
  • also, I am going to assume there should only be one instance of TaxiId in your db.Taxis, if this is true, then do db.Taxis.First(x => x.TaxiId == CurrenltySelectedTaxi.TaxiId) then assign the properties. (assuming that the taxi id already exists, use FirstOrDefault if it may not exist) Commented Jun 22, 2015 at 15:05
  • 1
    Added how the Driver is selected. CurrentlySelectedTaxi is select is the same way just from another place Commented Jun 22, 2015 at 15:14
  • Could it be that your event SelectIndexChanged is called twice? Commented Jun 22, 2015 at 15:24
  • It wouldn't make a difference if it was called twice, as it makes NO changes to the database Commented Jun 22, 2015 at 15:29

3 Answers 3

1

The only thing that I can possibly find based on the content you have provided is that CurrenltySelectedTaxi.Driver is a detached or new driver. Be careful to ensure that the object pointed to by CurrenltySelectedTaxi.Driver is an attached driver record.

An option you can do to help determine the status of that record is to put a breakpoint on that line and then look at the DbEntry record status.

Sign up to request clarification or add additional context in comments.

2 Comments

How can I check this? I populate the combo box like this ` listDrivers.Items.AddRange(db.Drivers.ToArray());` and select it like ` using (var db = new DataModel()) { db.Configuration.ProxyCreationEnabled = false; Driver listSelected = (Driver) cmbTaxiDriver.SelectedItem; CurrenltySelectedTaxi.Driver = db.Drivers.Where(x => x.DriverId == listSelected.DriverId).ToArray()[0]; }`
Don't add the entire record to the list and rely on the ToString() ... also ... do not keep your db context around very long ... only instantiate the db content when you are processing the transactions. Otherwise, load the lists/comboboxes with ID's and Titles ... assign the x.Driver directly to an object in a DbSet ... or stop using the navigation property and assign the DriverID column instead.
1

Your design doesn't create a relationship between Taxi and Driver that's going to translate to a database. Try something like this:

public partial class Taxi
    {
        public Taxi()
        {
        }
        public int TaxiId { get; set; }
        public int DriverId {get; set; }
        public virtual Driver Driver { get; set; }
        public string Make { get; set; }
        public string Model { get; set; }
        public Color Colour { get; set; }
        public string NumPlate { get; set; }
        public int MaxPassengers { get; set; }
}

You may also want to add the following to the Driver object:

public virtual IEnumerable<Taxi> Taxis { get; set; }

7 Comments

This is what I had originally and I removed it because of the issue
Just tested again with public virtual Driver Driver { get; set; }, I stepped through and DriverID = 2 after the db.SaveChanges() it changes to the next in the list(in this case 10, next test 11)
Are you still setting a value for the Driver property? Because that shouldn't be necessary (and may even be the problem) - the important thing is to set the DriverId property to the correct value.
Yes I set the Driver, but its correct up until db.SaveChanges() it changes INSIDE that function
Right, so DON'T set the Driver property. Just the DriverId. Or if you absolutely must set the driver property, make sure you tag it as being updated, because it sounds like EF is defaulting to it being a new object.
|
0

So it turns out my issue is because i followed the tutorial on MSDN that says to recreate your context EVERYTIME you use it. Although this 'may' be good practice, in this instance it caused the problem.

If I make one context for the entire class it works as expected/

1 Comment

Yes, but that leaves the connection to the database open, introducing other possible issues. What you want to do is ensure your context knows how to deal with the items you give it by setting the proper state for the entity: msdn.microsoft.com/en-US/data/jj592676

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.