Click here to Skip to main content
14,880,257 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
Hello everybody!

First of all sorry about my bad English.
I am a starting programmer and I have following problem.

With EF and a generic repository I can do an Insert and Delete without any problem.
The problem is invoked when I do an update on the same database and same object.

The error message is the following:
System.InvalidOperationException
Collection was modified; enumeration operation may not execute.

I have done some research but I can't solve of figuring out what is the problem...
The strange thing is that I use the same context as the select / or insert (so the collection must be the same).

Has anyone an idea?

Many thanks in advance!

the code:


this is the method in the generic repository

C#
public static T AddOrUpdate<T>(this DbContext context, T entity)
           where T : class
       {
           if (context == null) throw new ArgumentNullException("context");
           if (entity == null) throw new ArgumentNullException("entity");

           if (IsTransient(context, entity))
           {

               context.Set<T>().Add(entity);
           }
           else
           {
               context.Set<T>().Attach(entity);  //here I get the error
               context.Entry(entity).State = EntityState.Modified;
           }
           return entity;
       }


This is my damagecore

C#
public static Result NewDamage(Context ctx, CarDamage _newCarDamage)//Damage _newDamage)
        {
            
            
            GenericRepository<CarDamage> carCamageRepo = new GenericRepository<CarDamage>(ctx);
            carCamageRepo.AddOrUpdate(_newCarDamage);
            
            ctx.SaveChanges();
            
            return null;
        }




code behind the button

C#
private void save_Click(object sender, RoutedEventArgs e)
     {
         double invAmount;
         if (NoEmptyFieldsCheck() == false)
         {
             MessageBox.Show("Gelieve alle velden in te vullen", "Schade", MessageBoxButton.OK, MessageBoxImage.Warning);
             return;
         }
         if (DamageOverviewCheck() == false)
         {
             MessageBox.Show("Gelieve minstens 1 schade onderdeel toe te voegen", "Schade", MessageBoxButton.OK, MessageBoxImage.Warning);
             return;
         }
         if (Double.TryParse(invoiceAmount.Text, out invAmount)== false)
         {
             MessageBox.Show("Geef een geldig factuurbedrag","Schade", MessageBoxButton.OK, MessageBoxImage.Warning);
             return;
         }

        // Damage newDamage = new Damage();

        // CarDamage newCarDamage = new CarDamage() { Car = (Car)carComboBox.SelectedItem, ActualValue= true };
         carDamage.Car = (Car)carComboBox.SelectedItem;
         carDamage.ActualValue = true;

         newDamage.DamageDate = damageDate.SelectedDate ?? DateTime.Today;
         newDamage.DamageState = (DamageState)damageStateComboBox.SelectedItem;
         newDamage.DamageCauser = damageCauser.Text;
         newDamage.InvoiceAmount = (float)invAmount;
         newDamage.PaymentFranchiseDriver = paymentFranchiseDriver.IsChecked.Value;
         newDamage.PaymentOk = paymentOk.IsChecked.Value;
         newDamage.DamageOverview = damageOverview;

         if (accident.IsChecked == true)
         {
             Accident newAccident = new Accident();
             newAccident.AccidentFileDate = fileDate.SelectedDate ?? DateTime.Today;
             newAccident.FileState = (FileState)fileStateComboBox.SelectedItem;
             newAccident.AccidentDescription = accidentDescriptionTxtBox.Text;
             newDamage.Accident = newAccident;

         }

         if (files.Count > 0)
         {


             foreach (var file in files)
             {
                 Document doc = new Document();

                 string fileExtention = Path.GetExtension(file);
                 string fileName = Path.GetFileNameWithoutExtension(file);
                 string originalFilePath = Path.GetFullPath(file);
                 doc.FileDestination = @"C:\Users\Jeffry\Desktop\document.carma\" + doc.DocumentID + fileExtention;

                 doc.OriginalFileName = fileName;
                 doc.AdditionDate = DateTime.Today;
                 File.Copy(originalFilePath, doc.FileDestination);





             }
             newDamage.Document = docList;
         }

         carDamage.CarID = (int)carComboBox.SelectedValue;
         carDamage.ActualValue = true;
         carDamage.Damage = newDamage;
         DamageCore.NewDamage(mainWindow.ctx, carDamage);

         id = newDamage.DamageID; //getting id of last added damage (needed to go to documents for getting right documents)

     }



Added 15/04/2014


ObjectID is passed to constructor
C#
private void viewDetail_Click(object sender, RoutedEventArgs e)
       {
           CarDamage carDamage = (CarDamage)damageLV.SelectedItem;
           DamagePage damagePage = new DamagePage(mainWindow, carDamage.DamageID);
           mainWindow.MainFrame.Navigate(damagePage);
       }


Constructor of the page
C#
public DamagePage(MainWindow main, int damageId)
       {
           mainWindow = main;
           mainWindow.SetTitle("Detail schade");
           InitializeComponent();
           AddData();
           carDamage = DamageCore.GetDamage(mainWindow.ctx, damageId);
           //carDamage.CarDamageID = damageId;
           FillDataOnForm(carDamage);
       }



Code where i get CarDamage object and fill the form... is invoked by the constructor

C#
private void FillDataOnForm(CarDamage carDamage)
      {
          damageDate.SelectedDate = carDamage.Damage.DamageDate;
          carComboBox.SelectedValue = carDamage.CarID;
          damageStateComboBox.SelectedValue = carDamage.Damage.DamageStateID;
          damageCauser.Text = carDamage.Damage.DamageCauser;
          invoiceAmount.Text = carDamage.Damage.InvoiceAmount.ToString("0.00");

          paymentFranchiseDriver.IsChecked = carDamage.Damage.PaymentFranchiseDriver;
          paymentOk.IsChecked = carDamage.Damage.PaymentOk;
          accident.IsChecked = false;
          if (carDamage.Damage.AccidentID != 0)
          {
              accident.IsChecked = true;
              fileDate.SelectedDate = carDamage.Damage.Accident.AccidentFileDate;
              fileStateComboBox.SelectedValue = carDamage.Damage.Accident.FileStateID;
              accidentDescriptionTxtBox.Text = carDamage.Damage.Accident.AccidentDescription;
          }
          damageOverview = carDamage.Damage.DamageOverview;

          damagesLV.ItemsSource = null;
          damagesLV.ItemsSource = damageOverview;
          docList = carDamage.Damage.Document;
          id = carDamage.DamageID;



      }



Update 17/04/2014

Generic update
C#
public void Update(T entity)
        {
            var entry = _context.Entry(entity);
            if (entry.State == EntityState.Detached)
            {
                _context.Set<T>().Attach(entity);
                entry = _context.Entry(entity);
            }
            entry.State = EntityState.Modified;
        }


update 23/04/2014

I still have the same problem...

Here is my add or update method... (which also doesn't work... :( )
C#
public static T AddOrUpdate<T>(this DbContext context, T entity)
            where T : class
        {
            if (context == null) throw new ArgumentNullException("context");
            if (entity == null) throw new ArgumentNullException("entity");
            
            if (IsTransient(context, entity))
            {
                
                context.Set<T>().Add(entity);
            }
            else
            {
                // original
                context.Set<T>().Attach(entity);

// here i Get an error... and i don't know why...

//errormessage: Collection was modified; enumeration operation may not execute !!!!!!!!???????


                context.Entry(entity).State = EntityState.Modified;


                //test
                //context.Entry<T>(entity).State = EntityState.Modified;
                //context.Entry(entity).State = EntityState.Modified;
            }
            return entity;
        }
Posted
Updated 23-Apr-14 5:24am
v6
Comments
Richard C Bishop 14-Apr-14 15:17pm
   
Code please.
Dave Kreskowiak 14-Apr-14 15:20pm
   
Without seeing the code involved it's impossible to tell you what you did wrong.

1 solution

1.In the case of update the entity must have valid value(s) for its "primary key", so the EF to can find it in the DB and then to attach it to the current context.

2.So first you have to debug your code and check the 1st point above at the begging of method AddOrUpdate, and if the data that come are not OK, you should do changes at the place of invocation!

3.Your carDemage object should be created each time before to invoke AddOrUpdate method in your save_Click method like in the next code:
C#
CarDamage carDemage = new CarDemage();
carDemage.ID = ...; // must be set!
carDamage.ActualValue = ... // set the other properties!
//.. 

4.You are trying to attach an CarDamage object to your DbContext object, but the object is already attached to this EF context. So the solution is to just search for this object (by its ID), then set its changed properties, and finally SaveChanges().
   
v3
Comments
aanbidmij 15-Apr-14 6:14am
   
thanks for your answer, but the primary keys are loaded (first i did a selection) en show them in a list. When clicked on a list item the all the parameteres are loaded in the form.

The form itselfs prevends of getting wrong data...
and the Class CarDamage has an ID which is set correctly.

So I have no clue what could be wrong with the AddOrUpdate method...
Raul Iloc 15-Apr-14 7:05am
   
Where is your "carDemage" object created? Could you provide also that code? "carDemage" is a class memeber?
See my update!
aanbidmij 15-Apr-14 13:32pm
   
See my update...
As far as I can see the CarDamage.CarDamageID is set...
Raul Iloc 16-Apr-14 1:08am
   
See my update (4th point)!
aanbidmij 17-Apr-14 15:37pm
   
Thankyou for your reply, maybe you have the correct solution. But I don't get i how i can update my Database with my generic repository. (see code) All my entity's have a ID like CarID, CarDamageID, DocumentID. (I don't have a baseclass Entity which has an ID) For all clearness each entity has an other ID name...
Raul Iloc 24-Apr-14 3:45am
   
The name of the "ID" field is not important for my solution, the idea is to use the "primary key" or a "unique key" (in your case should be "CarDemageID") to load the entity that you need for update.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900