0

I am trying to add the same object(just changing a property) multiple time to the database, but the problem is after adding the first record to the database the record get an id and the other records cannot be added.

My model:

class MyClass{ 
    int id {set;get;}
    string name {set;get;}
    string color {set;get;}
    //and other properities.
}

My Controller :

public ActionResult Test(MyClass obj,int Counter){
    for(int i=0;i<Counter;i++){
        MyClass NewObject=obj;
        NewObject.name=obj.name+" "+i.ToString();
        Db.MyClass.Add(NewObject);
        Db.SaveChanges();
    }
 }

For example if my object is : name="theName";Color="Red"; And the counter is 3; So my expected output is :

  • First record: name="theName 0";Color="Red";
  • Second record: name="theName 1";Color="Red";
  • Third record: name="theName 2";Color="Red";

But what happens is after the first record be added NewObject will have an id but the problem that is obj have also id although I didn't add it to the database! So the second record will return an error ('The changes to the database were committed successfully, but an error occurred while updating the object context.')

3
  • 1
    You keep referencing the same object, so entity framework does an insert first and then updates the record counter - 1 times. Commented Apr 25, 2018 at 12:45
  • You should really stick to the .NET naming convention. If you name classes with lower case and local variables with Pascal case, you will make your code more difficult to read for most C# developers. Besides, you should also tag your question with the OR mapper you are using. Commented Apr 25, 2018 at 12:46
  • @Jerodev , Yeah exactly thats what is happening. But what is the right way to add an object multiple times to the database. Commented Apr 25, 2018 at 12:51

3 Answers 3

1

You should never use the same object to represent multiple objects in the DB. Under the hood, EF keeps references to data objects it knows and these references are significant.

If you want to add a lot of similar objects, there are multiple options for your. Two of them are:

Using a method to initailize the new objects

You could initialize multiple instances of your objects with a common method and only add the property values that are different (your method can also be a local function if you are using C# 7):

MyClass CreateInstance() {
    return new MyClass {
        Name = "theName";
        Color = "Red";
    }
}

public ActionResult Test(MyClass obj, int Counter){
    for(int i = 0; i < Counter; i++){
        MyClass newObject = CreateInstance();
        newObject.Name = newObject.Name + " " + i.ToString();
        Db.MyClass.Add(newObject);
        Db.SaveChanges();
    }
}

Make the object cloneable

You can make the object cloneable (you can implement the ICloneable interface, but this wouldn't be required here and its Clone method returns an object):

class MyClass{ 
    public int Id { set; get; }
    public string Name { set; get; }
    public string Color { set; get; }
    public MyClass Clone() {
        MyClass clone = (MyClass)MemberwiseClone();
        clone.Id = 0;
        return clone;
    }
}

public ActionResult Test(MyClass obj, int Counter){
    for(int i = 0; i < Counter; i++){
        MyClass newObject = obj.Clone();
        newObject.Name = obj.Name + " " + i.ToString();
        Db.MyClass.Add(newObject);
        Db.SaveChanges();
    }
}

Which option you you should use, depends entirely on your specific use case.

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

Comments

0

Assigning a complex object to another complex results in a pointer or reference to the source object, therefore, any modifications made will reflect to the one instance referenced by two variables. You can see this in .net by inspecting the hash code of the object. To deep-clone or make a copy you need to construct a new object in memory using new MyObject() and then copy the simple type values over. You will need to instantiate and copy all child properties that are themselves complex objects.

public ActionResult Test(MyClass obj,int Counter){
    for(int i=0;i<Counter;i++){
        MyClass NewObject=new MyClass();
        NewObject.name=obj.name+" "+i.ToString();
        NewObject.color = obj.color;
        Db.MyClass.Add(NewObject);
        Db.SaveChanges();
    }
 }

Comments

0

One approach would be to construct a new object each loop iteration with something like this (I've changed the variable names to match more common practices):

public ActionResult Test(MyClass baseObj,int Counter){
    for(int i=0;i<Counter;i++) {

        MyClass newObject = new MyClass()
        {
            Name = baseObj.Name,
            Color = baseObj.Color
        };

        Db.MyClass.Add(NewObject);
        Db.SaveChanges();
    }
 }

In an ideal situation however, this would be handled in the business logic layer to maintain Separation of Concerns. With this approach, construction of all your objects would happen before you called any methods adding to a database. You could then pass in a List<MyObject> and add the list using something like Db.MyClass.AddRange(listOfObjectsPassed) in a corresponding data layer method.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.