Bug in using AttachEntity and Navigation Property.
Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2010
Forum Discription: For .NET 4.0
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=3417
Printed Date: 13-May-2026 at 5:44am
Topic: Bug in using AttachEntity and Navigation Property.
Posted By: Walid
Subject: Bug in using AttachEntity and Navigation Property.
Date 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 { get; set; }
public string Name { get; set; }
[ForeignKey("Profession")]
public int ProfessionId { get; set; }
public Profession Profession { get; set; }
}
public class Profession : BaseEntity
{
[Key]
public int Id { get; set; }
[Required]
public string Title { get; set; }
}
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 http://www.ideablade.com/forum/uploads/998/ConsoleApplication3.zip - uploads/998/ConsoleApplication3.zip
|
Replies:
Posted By: DenisK
Date 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.
|
Posted By: Walid
Date 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.
-------------
|
Posted By: DenisK
Date 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.
|
Posted By: Walid
Date 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
-------------
|
Posted By: DenisK
Date 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.
uploads/912/ConsoleApplication3_Modified.zip - uploads/912/ConsoleApplication3_Modified.zip
|
Posted By: Walid
Date 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));
-------------
|
Posted By: Walid
Date 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);
}
}
-------------
|
Posted By: DenisK
Date 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.
|
Posted By: DenisK
Date 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.
|
Posted By: Walid
Date Posted: 22-May-2012 at 12:56am
|
Nice,
Thanks for the feedback.
|
|