1

I am having a strange problem: I have a quite simple Login(string user, string pass) method for user login which needs to save last login date of that user:

using (MyDbContext dbContext = new MyDbContext())
{
    var dbUser = dbContext.IdentityUserLogins.SingleOrDefault(u => 
        u.LoginProvider == login && u.ProviderKey == password);
    if (dbUser != null)
    {
        dbUser.LastLoginDate = DateTime.Now;
        dbContext.Entry(dbUser).State = System.Data.Entity.EntityState.Modified;
        dbContext.SaveChanges();
        var id = Convert.ToInt32(dbUser.UserId);

        /*other stuff*/
    }
}

When I run this from a regular debug, everything works fine. The user I enter is found, his LastLoginDate is updated successfully and its Autogenerated SysStartTime is updated automatically at SaveChanges()

But when I run this method from an xUnit test, it behaves strange. The test is simple, like this:

[Fact]
[Trait("Category", "MyCategory")]
public void LoginTest()
{
    string user = /*user name*/
    string pass = /*get password hash*/
    UserModel user = handler.Login(user, pass);
    Assert.NotNull(user);
}

It simply calls that method.

The problem occurs on SaveChanges() call, an exception is thrown:

Cannot update GENERATED ALWAYS columns in table 'AppIdentityUserLogin'

Our tables use these columns like SysStartTime, SysEndTime and RowVersion, but there are no problems with Entity Framework knowing, how to handle them, this is the only exception - this xUnit test.

The problem is most likely in the dbContext.Entry(dbUser)... line, because when I comment it out, the test passes normally. I even think it is not needed there, because without it everything updates the same in regular debug. EDIT: Both - xUnit tests and regular debug are using the same ConnectionString.

What could cause this strange behavior? I tried to find some pre-run config, some differences between accessing this method as a test debugger and as a regular debugger, but couldn't find anything.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
XzajoX
  • 23
  • 6
  • Where is your dbContext getting the connection string from? make sure they are pointing to the same database? – Aman B Jan 18 '18 at 17:23
  • Yes they are using the same connection string. I checked that. I updated my question. Thanks for pointing it out. – XzajoX Jan 19 '18 at 09:03
  • Since you are updating a connected entity, you don't need to mark the whole object as modified. When you set a new field value it'll automatically mark the specific field as modified. So dbContext.Entry isn't necessary in this scenario – Aman B Jan 19 '18 at 11:42
  • If you explicity want to mark one field as modified please see https://stackoverflow.com/questions/3642371/how-to-update-only-one-field-using-entity-framework – Aman B Jan 19 '18 at 11:42

1 Answers1

0

Solved it. Credit goes to Matt Ruwe and his solution to the Temporal table problem he had.

I simply had to tell EF, not to try to overwrite the Generated columns. In my case I had to set the _namesToIgnore to "SysStartTime" and "SysEndTime" and then put this line in my BaseTest constructor

System.Data.Entity.Infrastructure.Interception.DbInterception.Add(new EF.TemporalTableCommandTreeInterceptor());

Now everything inserts and updates normally even from xUnit test debug.

XzajoX
  • 23
  • 6