none
LTS and Cannot add an entity that already exists. RRS feed

  • Question

  • Hi I have a strange problem with linq ToSql:

    when ever I try to insert object second time i get exception of type: Cannot add an entity that already exists.

    the code is:

    and it fials on the second  um.CreateUser(testUser1);

                serviceFactory = new ClassServiceFactory();
                IUserManager um = (IUserManager)serviceFactory.FindByServiceName(USERMAN);
               User testUser = new User();
                testUser.Person = new Person
                {
                    Email = "testPerson@bop.com",
                    BelongsToSection = ""
                };
                testUser.Active = true;
                testUser.UserId = "testUser";
                testUser.Password = "testPassword";
                um.CreateUser(testUser);

                serviceFactory = new ClassServiceFactory();
                User testUser1 = new User();
                testUser1.Person = new Person
                {
                    Email = "testPerson@bop.com",
                    BelongsToSection = ""
                };
                testUser1.Active = true;
                testUser1.UserId = "testUser";
                testUser1.Password = "testPassword";
                um.CreateUser(testUser1);
    }

            public User CreateUser(User user)
            {
                IServiceFactory serviceFactory = new ClassServiceFactory();
                IDaoFactory df = (IDaoFactory)serviceFactory.FindByServiceName("Angel/Core/DataInterfaces/IDaoFactory");
                IPersonDao ipd = df.GetPersonDao();


                Person testPerson = user.Person;
                ipd.Save(testPerson);
                testPerson.AddRole(user);
                ipd.CommitChanges();

                return user;
            }

    if I read all the record then even the first createuser fails!

    without reading the data first then every first create works (after restarting th app each time)

     



    • Edited by liorba Monday, June 27, 2011 6:55 PM
    Saturday, June 18, 2011 2:20 PM

Answers

  • Ok, It's now solved. Don't mess with Equal with LTS. it seems that was the problem. I've also found this:

    http://mocella.blogspot.com/2009/04/linq-to-sql-and-overriding-equals-not.html

     

    Monday, June 27, 2011 3:09 PM

All replies

  • Hi liorba;

    Seeming that all the fields from both records have the same value does any of those field such as UserID unique constraint?

     


    Fernando

    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Saturday, June 18, 2011 5:38 PM
  • Hi, thanks for the reply

    I've additional column that is dbgenerated and auto inceremented and is the PK of the table.

    but even if I changed all the data for the second person still I get the exception.

    what is strange is that the first insert works on a new run of the application and add a record with the same details with the Key culom incremented.

    the second create fails but it is the same code as the first.

    the tables are stakeholder (Person inherits from stakeholder class) and Role (user inherits from Role class

    it's seems that it fails at the insert of the person at the line

    ipd.Save(testPerson);

    from the createUser method. Like there are two stakeholder but th PK is generate on insert only. all other fields can be the same.

    the save method:

            public virtual T Save(T entity)
            {
                ITable tab = db.GetTable(entity.GetType().BaseType);
                tab.InsertOnSubmit(entity); <- FAILS HERE
                this.CommitChanges();
                return entity;
            }

    part of the map file of both tables is as follow (there are more tables not shown here):

     <Table Name="Roles" Member="Roles" >
        <Type Name="Angel.Core.Domain.Role">
          <Column Name="RoleType" Member="RoleType" DbType="Int NOT NULL" IsDiscriminator="true" />
          <Column Name="RoleName" Member="Name" DbType="NVarChar(50)" CanBeNull="True"/>
          <Column Name="StakeHolderId" Member="StakeHolderId" DbType="Int NOT NULL" IsPrimaryKey="true" />
          <Association Name="FK_Roles_StakeHolders" Member="StakeHolders" ThisKey="StakeHolderId" OtherKey="StakeHolderId"  DeleteOnNull="true" IsForeignKey="true" />
          <Type Name="Angel.Core.Domain.User" InheritanceCode="0" IsInheritanceDefault="True">
            <Column Name="UserId" Member="UserId" DbType="NVarChar(50) NOT NULL" CanBeNull="false" />
            <Column Name="Password" Member="Password" DbType="NVarChar(50) NOT NULL" CanBeNull="false" />
            <Column Name="Active" Member="Active" DbType="BIT NOT NULL" CanBeNull="false" />
            <Column Name="UserRole" Member="UserRole" DbType="Int NOT NULL" CanBeNull="false" />
            <Column Name="UserType" Member="UserType" DbType="Int NOT NULL" CanBeNull="false" />
          </Type>
        </Type>
      </Table>
      
      <Table Name="StakeHolders" Member="StakeHolders">
        <Type Name="Angel.Core.Domain.StakeHolder">
          <Column Name="StakeHolderType" Member="StakeHolderType" DbType="Int NOT NULL" IsDiscriminator="true" UpdateCheck="Never"/>
          <Column Name="StakeHolderId" Member="StakeHolderId" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" AutoSync="OnInsert"/>
          <Column Name="Timestamp" Member="Timestamp" DbType="rowversion NOT NULL" CanBeNull="False" IsDbGenerated="true" IsVersion="true" />
          <Association Name="FK_Roles_StakeHolders" Member="Roles" ThisKey="StakeHolderId" OtherKey="StakeHolderId" DeleteRule="CASCADE" IsUnique="true" />
          <Association Name="FK_Tasks_StakeHolders" Member="Documents" ThisKey="StakeHolderId" OtherKey="TaskAssignedToStakeHolderId" DeleteRule="NO ACTION" IsUnique="true" />
          <Association Name="FK_Persons_StakeHolders" Member="StakeHolders" ThisKey="StakeHolderId" OtherKey="AdministratedByStakeHolderId" DeleteRule="NO ACTION" IsUnique="true" />
          <Association Name="FK_CustomerCalls_StakeHolders" Member="Documents" ThisKey="StakeHolderId" OtherKey="CustomerCallTaskAssignedToStakeHolderId" DeleteRule="NO ACTION" IsUnique="false" />
     
          <Type Name="Angel.Core.Domain.Person" InheritanceCode="0" IsInheritanceDefault="True">
            <Column Name="FirstName" Member="FirstName" DbType="NVarChar(50)" CanBeNull="True"/>
            <Column Name="LastName" Member="LastName" DbType="NVarChar(50)" CanBeNull="True"/>
            <Column Name="Gender" Member="Gender" DbType="Char(1)" CanBeNull="True" UpdateCheck="Never"/>
            <Column Name="DOB" Member="DOB" DbType="DateTime" UpdateCheck="Never"/>
            <Column Name="Email" Member="Email" DbType="NVarChar(100) NOT NULL" CanBeNull="True" UpdateCheck="Never"/>
            <Column Name="TaxId" Member="TaxId" DbType="NVarChar(50)" CanBeNull="True" UpdateCheck="Never"/>
            <Column Name="JobTitle" Member="JobTitle" DbType="NVarChar(50)" CanBeNull="True" UpdateCheck="Never"/>
            <Column Name="AdministratedByStakeHolderId" Member="AdministratedByStakeHolderId" DbType="Int NOT NULL" CanBeNull="true" />
            <Column Name="BelongsToSection" Member="BelongsToSection" DbType="NVarChar(255) NOT NULL" CanBeNull="true" />
            <Column Name="IsObsolete" Member="IsObsolete" DbType="BIT NOT NULL" CanBeNull="false" />
            <Association Name="FK_Persons_StakeHolders" Member="StakeHolders" ThisKey="AdministratedByStakeHolderId" OtherKey="StakeHolderId" IsForeignKey="true" />
            <Association Name="FK_Documents_StakeHolders" Member="StakeHolders" ThisKey="StakeHolderId" OtherKey="StakeHolderId" DeleteRule="NO ACTION" />
          </Type>
        </Type>
      </Table>

    and if do a read first than the first createuser also fails. The read is by Get all method:

            public List<Person> GetAll()
            {
                IServiceFactory serviceFactory = new ClassServiceFactory();
                IDaoFactory df = (IDaoFactory)serviceFactory.FindByServiceName("Angel/Core/DataInterfaces/IDaoFactory");
                IPersonDao ipd = df.GetPersonDao();

                return ipd.GetAll();
            }
    Saturday, June 18, 2011 6:03 PM
  • Hello,

    Thank you for posting.

    After checked your post, I think your question might be related that you’re trying to insert the same entity over and over, but you created only one instance ”um” and always used this instance in the insert.

    I suggest you can check to iterate these operations in the foreach and create a new instance of IUserManager object and the insert operation should work OK. In addition, I suggest you can check to do CommitChanges once after the foreach loop instead everytime you iterated.

    Hope this helps.

    Best Regards,


    Larcolais Gong[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, June 21, 2011 6:47 AM
  • Hello,

    Thank you for posting.

    After checked your post, I think your question might be related that you’re trying to insert the same entity over and over, but you created only one instance ”um” and always used this instance in the insert.

    I suggest you can check to iterate these operations in the foreach and create a new instance of IUserManager object and the insert operation should work OK. In addition, I suggest you can check to do CommitChanges once after the foreach loop instead everytime you iterated.

    Hope this helps.

    Best Regards,


    Larcolais Gong[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.


    but I'm not rying to insert the same entity twice. I've different data in the user. When should I need two UserManager instance?  this class just contains the CRUP operation and if I do getALL (and not insert) than even the first insert fails so I don't thing it is an insert of the same entity...

    This is really frustrating.

    Even when using two instances it's still fails on the second insert:

     

    [Test]
            public void CreateUser()
            {
                serviceFactory = new ClassServiceFactory();
                IUserManager um = (IUserManager)serviceFactory.FindByServiceName(USERMAN);

                User testUser = new User();
                testUser.Person = new Person
                                      {
                                          Email = "testPersonaaa@bop.com",
                                          BelongsToSection = "",
                                          AdministratedByStakeHolderId = 2
                                      };
                testUser.Active = true;
                testUser.UserId = "testUseaaaaaar";
                testUser.Password = "testPasswordaaaaaaa";
                um.CreateUser(testUser);

                serviceFactory = new ClassServiceFactory();
                IUserManager um1 = (IUserManager)serviceFactory.FindByServiceName(USERMAN);
                User testUser1 = new User();
                testUser1.Person = new Person
                                       {
                                           Email = "te1stPerson@bop111111.com",
                                           BelongsToSection = "",
                                           AdministratedByStakeHolderId = 100

                                       };
                testUser1.Active = true;
                testUser1.UserId = "testUser1";
                testUser1.Password = "testPassword1";
                um1.CreateUser(testUser1);

            }

     


            public User CreateUser(User user)
            {
                IServiceFactory serviceFactory = new ClassServiceFactory();
                IDaoFactory df = (IDaoFactory)serviceFactory.FindByServiceName("Angel/Core/DataInterfaces/IDaoFactory");
                IPersonDao ipd = df.GetPersonDao();


                Person testPerson = user.Person;
                ipd.Save(testPerson); <--- calls the one belows
                testPerson.AddRole(user);
                ipd.CommitChanges();

                return user;
            }


            public virtual T Save(T entity)
            {
                ITable tab = db.GetTable(entity.GetType().BaseType);
                tab.InsertOnSubmit(entity); <------------------ FAILS HERE
                this.CommitChanges();
                return entity;
            }
    Friday, June 24, 2011 7:00 AM
  • I think I've solved this!

    It seems like even when the ID field is dbgenerated I, never the less, need to assigned a value to this field that is not the same as existing id but It is strange since I thought that LTS does all the backgroud work on the DB: why should I set a field to same value when the insert set it to the next value anywhy?

    the second inser works when seting ID =100 andthere are 5 users. after the insert it changed to value 6.

    and if I have multiple logins how can I verify that no two user have the same ID? why should I even touch/set the ID field when it is DB GENERATED?

    and should I write a method to get the next ID for the next insert so I'll never have an exsiting ID? 

    Doesn't it defeat the porpuse of ORM in that I do not need  to work on the DB layer itself (and should not need) with DB logic (such as SQL nextVal?)




    Friday, June 24, 2011 8:44 AM
  • It seems InsertOnSubmit is using the Equals method. Maybe I've implemented it wrong... Where can I find the InsertOnSubmit conditions that LTS uses for determine if object is already in database and already exist??

    Friday, June 24, 2011 5:55 PM
  • Ok, It's now solved. Don't mess with Equal with LTS. it seems that was the problem. I've also found this:

    http://mocella.blogspot.com/2009/04/linq-to-sql-and-overriding-equals-not.html

     

    Monday, June 27, 2011 3:09 PM