【问题标题】:entity framework (MSSQL 2016) + xUnit test - tries to update "GENERATE ALWAYS" column SysStartTime实体框架 (MSSQL 2016) + xUnit 测试 - 尝试更新“GENERATE ALWAYS”列 SysStartTime
【发布时间】:2018-01-18 13:00:08
【问题描述】:

我遇到了一个奇怪的问题: 我有一个非常简单的 Login(string user, string pass) 用户登录方法,需要保存该用户的上次登录日期:

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*/
    }
}

当我从常规调试中运行它时,一切正常。找到我输入的用户,他的 LastLoginDate 更新成功,其 Autogenerated SysStartTime 在 SaveChanges() 自动更新

但是当我从 xUnit 测试中运行这个方法时,它的行为很奇怪。 测试很简单,像这样:

[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);
}

它只是调用那个方法。

调用SaveChanges()时出现问题,抛出异常:

Cannot update GENERATED ALWAYS columns in table 'AppIdentityUserLogin'

我们的表使用这些列,如 SysStartTime、SysEndTime 和 RowVersion,但 Entity Framework 知道如何处理它们没有问题,这是唯一的例外 - 这个 xUnit 测试。

问题很可能出在 dbContext.Entry(dbUser)... 行,因为当我将其注释掉时,测试正常通过。我什至认为那里不需要它,因为没有它,在常规调试中所有的更新都是一样的。 编辑:两者 - xUnit 测试和常规调试都使用相同的 ConnectionString。

什么可能导致这种奇怪的行为?我试图找到一些预运行配置,作为测试调试器和常规调试器访问此方法之间的一些差异,但找不到任何东西。

【问题讨论】:

  • 您的 dbContext 从哪里获取连接字符串?确保它们指向同一个数据库?
  • 是的,他们使用相同的连接字符串。我检查了那个。我更新了我的问题。感谢您指出。
  • 由于您正在更新一个连接的实体,您不需要将整个对象标记为已修改。当您设置新字段值时,它会自动将特定字段标记为已修改。所以在这种情况下不需要 dbContext.Entry
  • 如果您明确想将某个字段标记为已修改,请参阅stackoverflow.com/questions/3642371/…

标签: c# sql-server entity-framework sql-server-2016 xunit.net


【解决方案1】:

解决了。 感谢 Matt Ruwe 以及他对 Temporal table problem 的解决方案。

我只需要告诉 EF,不要尝试覆盖 Generated 列。 就我而言,我必须将 _namesToIgnore 设置为“SysStartTime”和“SysEndTime”,然后将此行放入我的 BaseTest 构造函数中

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

现在,即使从 xUnit 测试调试,一切都可以正常插入和更新。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 2019-07-07
    • 1970-01-01
    相关资源
    最近更新 更多