EF SaveChanges() throws an exception 'The EntityKey property can only be set when the current value of the property is null'
I have been reading all similar posts I found regarding EF but I can't still manage to found a solution.
I'm very new to the EF and I have been reading some useful info about working with it but I think that I'm missing something.
The scenario is like this:
I want a user to be able to create an account in an ASP.NET webpage. So I have a table named 'Accounts'. The user must agree with the condition terms of the site, that may be updated in the futere, so I have also a table called 'ConditionTerms' that has 1 to many relation with the account (many accounts have an unique condition term).
I wanted to separete the specific personal user data from the data of the account so I also created a table called 'Persons' and I set the relation ship so that a person may have many accounts.
Now, when I want to save an account into the database, I retrieve the last conditionTerm available in the database and I attach it to the account entity. Then when I try to save the data via SaveChanges() I get the exception mentioned in the title of the post. The thing is that if all entities are new, when the开发者_Go百科 associations are created, the EntityState for all the items is 'Detached' and it works, but when I retrieve the existing conditionTerm from the data base and I add it to the account.ConditionTerm, the account changes its state to 'Added' and then it throws the exception.
I read somewhere that when this happens, it means that all the entity tree is considered as already added by the context and I should only need to call SaveChanges() without the AddObject() method since it is already added. I tried this and then I get no exception and the code ends, but then if I check the database (SQL Server 2008 express) the account hasn't been added at all.
This is the code I'm trying and I think it should work but it's clear that I'm missing something:
[TestMethod]
public void TestCreateNewAccount()
{
try
{
AccountRepository accountRepository = new AccountRepository();
Account account = new Account()
{
Username = "TestUsername",
Password = "TestPassword",
Email = "TestEmail",
Nickname = "TestNickName",
Quote = "Test Quote",
AgreedToTermsDate = DateTime.Now,
CreationDate = DateTime.Now,
LastUpdateTime = DateTime.Now
};
// This works (all new entities!)
//ConditionTerm conditionTerm = new ConditionTerm()
//{
// Text = "This is some test condition term.",
// CreationDate = DateTime.Now,
// LastUpdateTime = DateTime.Now
//};
//This does not work (attaching an existing entity to a new one)
ConditionTerm conditionTerm = new ConditionTermsRepository().GetCurrentTerm();
Person person = new Person()
{
FirstName = "TestName",
Surname = "TestSurname",
CreationDate = DateTime.Now,
LastUpdateTime = DateTime.Now
};
account.ConditionTerm = conditionTerm;
account.Person = person;
using (ImproveEntities entities = Connection.GetModel())
{
if (account.ID > 0)
{
Account newAccount = new Account();
newAccount.ID = account.ID;
entities.Accounts.Attach(newAccount);
entities.Accounts.ApplyCurrentValues(account);
}
else
{
entities.Accounts.AddObject(account);
entities.SaveChanges();
}
}
}
catch (Exception)
{
}
}
Any help would be very much apreciated!
EDIT: This is the GetCurrentTerm() method:
public ConditionTerm GetCurrentTerm()
{
using (ImproveEntities entities = Connection.GetModel())
{
ConditionTerm conditionTerm = (from ct in entities.ConditionTerms
orderby ct.CreationDate descending
select ct).FirstOrDefault();
return conditionTerm;
}
}
If I understand correctly you want to insert a new account along with a new user into the database. But you don't want to create a new ConditionTerm
but instead assign an existing ConditionTerm
to the account.
The problem is that you fetch the existing ConditionTerm
in another context (in your GetCurrentTerm
) than the context you use for saving the new account. This second context doesn't know anything about the ConditionTerm
, so you must EF explicitely tell that this conditionTerm already exists by attaching it to the second context:
// ...
using (ImproveEntities entities = Connection.GetModel())
{
entities.ConditionTerms.Attach(conditionTerm);
account.ConditionTerm = conditionTerm;
account.Person = person;
entities.Accounts.AddObject(account);
entities.SaveChanges();
}
// ...
精彩评论