简体   繁体   中英

In EF6 Code First can I change a navigation property value, then break the relationship, and have both changes saved in one transaction?

I'm using Entity Framework 6 Code First to model a user/session relationship:

  • A user can have many sessions
  • Each session belongs to a single user
  • A user may also have a current session

My entities look like this (I've removed everything but those properties relating to my problem):

class User
{
    public int Id { get; set; }
    [ForeignKey("CurrentSession")]
    public int? CurrentSessionId { get; set; }
    public virtual Session CurrentSession { get; set; }
    [InverseProperty("User")]
    public virtual ICollection<Session> Sessions { get; set; }
}

class Session
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public virtual User User { get; set; }
    public string X { get; set; }
}

This creates the appropriate foreign key relationships in the database (optional FK from User to Session on CurrentSessionId column; required FK from Session to User on UserId column) so I'm happy with that.

What I'm trying to do is load a user and its current session, change a property value on the CurrentSession ( X in this example), remove the relationship between the user and the session (think: "user's session is no longer current"), then save both changes as a single transaction (ie. a single call to SaveChanges ).

Unfortunately, whichever way I try to modify the entity properties it always results in the User entity change being saved (SQL UPDATE on User table) but not the Session entity change. I could really do with this pair of updates being atomic. Is there any way of doing that or must I be forced to perform two separate SaveChanges calls?

Thus far I've tried this:

user.CurrentSession.X = ...;
user.CurrentSession = null;
dbContext.SaveChanges();

and this:

user.Sessions.Add(user.CurrentSession);
user.CurrentSession.X = ...;
user.CurrentSession = null;
dbContext.SaveChanges();

and this:

Session currentSession = user.CurrentSession;
user.CurrentSession = null;
currentSession.X = ...;
dbContext.Sessions.Attach(currentSession);
dbContext.Entry(currentSession).State = EntityState.Modified;
dbContext.SaveChanges();

But as soon as I set CurrentSession to null , EF effectively 'loses' the changes I make to the session entity.

It's okay, it does seem to work after all, even the simplest first code example.

The thing that threw me was that I have a basic DbCommandInterceptor class running that is just echoing the SQL statements to the debug console, and this only shows a single SQL UPDATE command despite two different tables being updated. I'm not sure why that's happening. Here's the code for the interceptor:

class DummyInterceptor : DbCommandInterceptor
{
    public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        base.ReaderExecuting(command, interceptionContext);
        Debug.WriteLine(new string('=', 70));
        Debug.WriteLine(command.CommandText);
    }
}

Thinking about it now, maybe it's because I'm only overriding the ReaderExecuting method? Need to check that out later.

UPDATE

Yes, that was what it was. I overrided (overrode?) the ScalarExecuting and NonQueryExecuting methods and then I saw the other SQL UPDATE query. The reason the two were in different 'groups' was because the User table has a rowversion column on it, and EF was getting the new row version after performing the FK update.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM