1

How can i insert object twice in database with different value when the object User has Code > 10 then it insert 2 object but some how EF update the value of the first inserted object.

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Code { get; set; }

}

and in my action i'm saving to databse

// Post Action
     uow.Users.Add(user);
     uow.Commit(); // save first time
    if (user.Code > 10)
    {
        user.Name = "NAS";
        uow.Users.Add(user);
        uow.Commit(); //save second time
    }

My object is

User = (Name = "Mike",Code=12)

Database result is

    Result Database
    id =1  Name="NAS" Code=12
    id =2  Name="NAS" Code=12
tereško
  • 58,060
  • 25
  • 98
  • 150
Maro
  • 2,579
  • 9
  • 42
  • 79
  • 1
    EF has smart change-tracking and it knows that you added the same object twice, so it simply tracks the ref. Create two separate objects. – NWard Mar 09 '16 at 20:36
  • Do i have to copy each property or is there a built in function? ICloneable is not supported any more. (atmk) – Maro Mar 09 '16 at 20:45

2 Answers2

4

This is correct behavior; so why is this happening:

  • When you save the first time, it creates a new entry in the database using your originally created user object.
  • When you save the second time, it takes the original object, which for lack of a better term, has a database reference and updates the name of the object AND it also adds that same object to the collection again; this is why you are seeing the same information in the database.

Your code should be:

var user = new User { Name = "Mike", Code = 12 };
uow.Users.Add(user);
uow.Commit();  // save first time

if (user.Code > 10)
{
    var newUser = new User { Name = "NAS", Code = user.Code };
    uow.Users.Add(newUser);
    uow.Commit(); //save second time
}

Your results should then be:

Result Database
id = 1  Name = "Mike" Code = 12
id = 2  Name = "NAS"  Code = 12
drneel
  • 2,887
  • 5
  • 30
  • 48
  • Well, the user calss was just an example, the class is designed with 33 property including many reference to another objects , according to your solution i have to copy each property? – Maro Mar 09 '16 at 20:47
  • @Maro - So that's a different question and to my knowledge there's no `easy` way. There are a number of answers available on SO with ideas; you can start here and move up the duplicate chain: http://stackoverflow.com/questions/6569486/creating-a-copy-of-an-object-in-c-sharp – drneel Mar 09 '16 at 20:53
  • Too bad that there is no simple copy object exists in .NET framework – Maro Mar 09 '16 at 20:55
  • 2
    Use automapper to clone the properties from the first to the second, then change the properties you care about. – NWard Mar 09 '16 at 20:57
  • @NWard I was just going to suggest that – drneel Mar 09 '16 at 20:58
  • 1
    I've seen solutions to deep copy using the BinarySerializer as well. – Kevin Mar 09 '16 at 20:58
  • @Maro I like the accepted answer here; it might be what Kevin was referring to. http://stackoverflow.com/questions/129389/how-do-you-do-a-deep-copy-an-object-in-net-c-specifically – drneel Mar 09 '16 at 21:08
  • @drneel Thanks i will give it a try – Maro Mar 09 '16 at 21:29
1

drneel gave a good explanation on why your code does not work as you intended.

Now maybe there is a workaround for what you want to achieve: inserting two distinct entities in DB from a single instance. Detach it from context, change what needs to be changed, re-add it.

If your uow is inheriting from DbContext, it would be:

var user = new User { Name = "Mike", Code = 12 };
uow.Users.Add(user);
uow.Commit();  // save first time

if (user.Code > 10)
{
    uow.Entry(user).State = EntityState.Detached;
    user.Id = 0;
    user.Name = "NAS";
    uow.Users.Add(user);
    uow.Commit(); //save second time
}

I am not comfortable with the way we have to detach entities in EF. It may work better to instead dispose your uow after first 'save' and use another one for second 'save'.

The main risk concerns navigation properties. Detaching does not ends tracking on collection of other entities which may hold a reference to your user instance. Re-adding it may screw EF navigation properties bookkeeping. (I would not fear that with NHibernate, such bookkeeping is not handled by NH. It remains the responsibility of the developer with NH.)

Frédéric
  • 9,364
  • 3
  • 62
  • 112