开发者

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();
    }
    // ...
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜