实体框架核心:SqlException:从服务器

时间:2017-08-30 15:02:52

标签: c# entity-framework asp.net-core entity-framework-core

我有一个由EF Core Code First DB支持的基本ASP.NET Core应用程序。简单地说,我刚刚添加了一些新的功能来操作附加到某个父对象的数据对象的集合,这似乎没有任何可解释的原因而失败。

父对象:

public class Character
{
    public Guid Id { get; set; }
    // int/string properties omitted
    public ICollection<CharacterMerit> CharacterMerits { get; set; }
}

有问题的对象:

public class CharacterMerit
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public Guid CharacterId { get; set; }

    public MeritKey MeritKey { get; set; } // enum
}

此列表在两个位置更新 - 角色创建,以及专门针对这些优点的单独操作&#39;。单独的操作只是将这些CharacterMerit对象的列表作为JSON接收,确保字符对象存在并将它们抛出到存储库层。这里没问题。

启动:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>(options =>
        {
            options.Password.RequireNonAlphanumeric = false;
        })
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddMvc();

    // Add application services.
    services.AddScoped<ISheetsRepository, SheetsRepository>();
    services.AddTransient<IViewModelFactory, ViewModelFactory>();
    services.AddTransient<SeedAdminRole>();
}

存储库:

public bool UpdateMerits(Guid characterId, List<CharacterMerit> merits)
{
    var dbCharacter = _dbcontext.Characters.Include(c => c.CharacterMerits).First(c => c.Id == characterId);

    if (dbCharacter.CharacterMerits.Any())
    {
        _dbcontext.CharacterMerits.RemoveRange(dbCharacter.CharacterMerits);
        dbCharacter.CharacterMerits = null;
        _dbcontext.SaveChanges();
    }

    dbCharacter.CharacterMerits = merits;

    _dbcontext.SaveChanges();

    return true;
}
public bool AddOrUpdateCharacter(Character character, bool date = true)
{
    if (date)
    {
        character.LastUpdated = DateTime.Now;
    }

    if (_dbcontext.Characters.FirstOrDefault(c => c.Id == character.Id) == null)
    {
        _dbcontext.Characters.Add(character);
    }
    else
    {
        _dbcontext.Characters.Update(character);
    }

    _dbcontext.SaveChanges();
    return true;
}

问题在于角色创造。 创建行动:

[HttpPost]
public async Task<IActionResult> Create(BasicInfoViewModel viewModel)
{
    var character = new Character
    {
        // property initialisation omitted for brevity
        // Id property is not initialised here, EF does this            
    };

    if(viewModel.Species != "Other")
    {
        character.CharacterMerits = new List<CharacterMerit>();
        character.CharacterMerits.Add(new CharacterMerit
        {
            MeritKey = MeritKey.Default; // for sake of example
        });
    }

    _repository.AddOrUpdateCharacter(character); // just adds the Character object to collection in dbcontext and calls SaveChanges()

    // redirect to another action
}

每当我尝试执行此操作时,我都会收到以下错误(有趣的是,它没有被调试器捕获,只是直接进入浏览器,包含在DbUpdateException中)。它似乎在SaveChanges()来电时失败了。

System.Data.SqlClient.SqlException: A transport-level error has occurred when receiving results from the server. (provider: Session Provider, error: 19 - Physical connection is not usable)
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
at System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()
at System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()
at System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()
at System.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte& value)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
at System.Data.SqlClient.SqlDataReader.get_MetaData()
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, String executeMethod, IReadOnlyDictionary`2 parameterValues, Boolean closeConnection)
at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
ClientConnectionId:998c6223-efc9-4172-a344-4b2ba71cf4c9
Error Number:-1,State:0,Class:20

如果我删除添加到CharacterMerits列表中的代码,一切都会顺利进行。 我试过了什么?

  • 在AddOrUpdateCharacter()调用
  • 之后移动列表操作
  • 以上,除了首先从数据库中检索新创建的Character对象外。
  • 初始化一个新列表(而不是操纵控制器中的Character对象)并使用上面的UpdateMerits()方法
  • 将存储库设置为transient,而不是Startup
  • 中的作用域

我已经考虑过将此操作重定向到另一个可以执行此操作的操作,但是从概念的角度来看,此代码属于此操作,如果存在,则无法解决根本问题。 应用程序当前正在localdb上运行,但是在标准SQL Server数据库上也运行了部署版本。 这不是我第一次使用EF中的集合,所以我对这里的错误感到困惑。

1 个答案:

答案 0 :(得分:0)

此异常似乎表明连接已被删除。您使用的是Azure还是其他任何云提供商?无论如何,我建议你试试EF Core的connection resiliency功能。