New Posts New Posts RSS Feed: Bug in using AttachEntity and Navigation Property.
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Bug in using AttachEntity and Navigation Property.

 Post Reply Post Reply
Author
Walid View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Nov-2010
Posts: 161
Post Options Post Options   Quote Walid Quote  Post ReplyReply Direct Link To This Post Topic: Bug in using AttachEntity and Navigation Property.
    Posted: 30-Apr-2012 at 10:41am
Hi,

Currently working with AttachEntity for the Faking (faking isn't relevant in this case), I have a strange behavior when I set a navigation property.

Considering those 2 entities :

    public class User : BaseEntity
    {
        [Key]
        public int Id { getset; }
 
        public string Name { getset; }
 
        [ForeignKey("Profession")]
        public int ProfessionId { getset; }
        public Profession Profession { getset; }
    }
 
    public class Profession : BaseEntity
    {
        [Key]
        public int Id { getset; }
 
        [Required]
        public string Title { getset; }
    }

What works :
1 - I create a Profession with Id 1 and DOESN'T attach it to the manager.
2 - I create a user with Id 1 and set the Profession to the User
=>  user.Id == 1

What doesn't work :
1 - I create a Profession with Id 1 and attach it to the manager.
2 - I create a user with Id 1 and set the Profession to the user
=> user.Id == -100


Here is a test  application uploads/998/ConsoleApplication3.zip


Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 30-Apr-2012 at 4:35pm
Hi Walid,

By default, User.Id and Profession.Id are Identity columns when doing Code First unless you specify it otherwise by marking it as such.

[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]

An identity column/id will be assigned a new temporary id as soon as it is attached or added to the EntityManager. In your "what doesn't work" scenario, when you create a User with Id 1, it is still unattached. But as soon as you're setting its User.Profession property to an already attached/added Profession entity, the unattached User will be attached and its Id will automatically be set to a temp Id overwriting whatever Id it was set to.
Back to Top
Walid View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Nov-2010
Posts: 161
Post Options Post Options   Quote Walid Quote  Post ReplyReply Direct Link To This Post Posted: 30-Apr-2012 at 4:47pm
hi Denis,

thanks, i thought attach doesn't touch the key, but only add it in the unchanged state.

so the "best practice" is to attach an entity right after it has been created and to set the navigation properties in last.
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 30-Apr-2012 at 5:36pm
Hi Walid,

My apologies, but you're correct. AttachEntity is NOT the same as AddEntity. Our DRC says,

"theEntity’s EntityKey (“the key”) must be preset prior to the attach operation (which will not touch the key)."

which confirms what you said above.

Now with this said, I just ran your sample and I don't see user.Id changes to -100. It stayed at 2 in both cases.
Back to Top
Walid View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Nov-2010
Posts: 161
Post Options Post Options   Quote Walid Quote  Post ReplyReply Direct Link To This Post Posted: 01-May-2012 at 1:32am
Strange, the assert fail each time for me. 
i am using Devforce 6.1.6 and EntityFramework 4.3.1

 




Edited by Walid - 01-May-2012 at 1:49am
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 01-May-2012 at 6:39pm
Hi Walid,

Not sure what happened but I can finally see the assert failed. I've modified the solution and added some comments to illustrate the correct way to achieve what you want.

Back to Top
Walid View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Nov-2010
Posts: 161
Post Options Post Options   Quote Walid Quote  Post ReplyReply Direct Link To This Post Posted: 02-May-2012 at 12:48am

Hi Denis,

Thanks but only one of those workaround works and it isn't always applicable.
The workaround where we attach first then set the navigation property change the entitystate of the entity which is not what we want (or we would have use AddEntity).
 
In fact, what you said earlier is what is happening. Setting a navigation property to an already attached/added entity will add the entity to the EM and set the auto generated Id. Attaching isn't the real cause.
 
The workaround where I attach all the entities in last (after all the settings is done) might not be applicable in some case. Sometimes, the entity I want to use for my navigation property been attached "somewhere else".
How can I deal with this issue in an elegant way ? Attaching, changing back the Id, updating the entitystate doesn't sound like a solution to me when you have to deal with hundreds of entities.
 
 
 
This exemple show AttachEntity isn"'t the real problem.
        var profession = new Profession()
        {
            Id = 1,
            Title = "Boss",
        };
        manager.AttachEntity(profession);
 
 
        var user = new User
        {
            Id = 2,
            Name = "User test with Profession",
        };
 
        user.Profession = profession;
        Debug.Assert(user.Id == 2, string.Format("Id expected = 2 - Id current value = {0} ", user.Id));
 
Back to Top
Walid View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Nov-2010
Posts: 161
Post Options Post Options   Quote Walid Quote  Post ReplyReply Direct Link To This Post Posted: 02-May-2012 at 3:36am
There is another problem. I made a function which  first create all the entities and set all the navigation properties, then attach them to the manager.

The Navigation properties are correctly set but all the foreignkey are set to 0. 
Note : AddEntities does correctly update the foreignKey;


        private static void Test4()
        {
            var manager = new TestEntities();
 
            var professions = new List<Profession>()
                                {
                                    new Profession()
                                        {
                                            Id = 1,
                                            Title = "Profession 1",
                                        },
                                        new Profession()
                                            {
                                                Id = 2,
                                                Title = "Profession 2",
                                            },
                               };
 
            var users = new List<User>()
                            {
                                new User()
                                    {
                                        Id = 1,
                                        Name = "User 1",
                                        Profession = professions[0],
                                    },
                                new User()
                                    {
                                        Id = 2,
                                        Name = "User 2",
                                        Profession = professions[1],
                                    }
                            };
 
 
            manager.AttachEntities(professions);
            manager.AttachEntities(users);
 
            foreach (var user in users)
            {
                // Navigation property is correctly set
                Debug.Assert(!EntityAspect.Wrap(user.Profession).IsNullOrPendingEntity);
                // The foreignkey isn't set
                Debug.Assert(user.ProfessionId == 0);
            }
        }



Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 03-May-2012 at 4:20pm
Hi Walid,

Thanks for pointing out that possible bug. Let me find out whether it's a real bug and file a report as necessary.

For now, I'm suggesting to use the first workaround with the addition of calling AcceptChanges on the entity.

     var manager = new TestEntities();

      var profession = new Profession() {
        Id = 1,
        Title = "Boss",
      };
      if (attachProfession)
        manager.AttachEntity(profession);

      var user = new User {
        Id = 2,
        Name = "User test with Profession",
      };

      manager.AttachEntity(user);
      user.Profession = profession;

      //Call AcceptChanges to make the user's state change from Modified to Unchanged
      EntityAspect.Wrap(user).AcceptChanges();

Please let me know if this works for you or not.
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 21-May-2012 at 12:29pm
Hi Walid,

Just want to let you know that the AttachEntity bug as you reported above has been fixed. It'll be included in the next release.
Back to Top
Walid View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Nov-2010
Posts: 161
Post Options Post Options   Quote Walid Quote  Post ReplyReply Direct Link To This Post Posted: 22-May-2012 at 12:56am
Nice,

Thanks for the feedback.
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down