2017-08-30 23 views
0

EFコアコードファーストDBに基づいた基本的なASP.NETコアアプリケーションがあります。簡単に言えば、いくつかの親オブジェクトにアタッチされたデータオブジェクトのコレクションを操作する新しい機能を少し追加しました。これは明らかに理由がないために転倒しています。エンティティフレームワークコア:SqlException:サーバーから結果を受け取ったときにトランスポートレベルのエラーが発生しました

親オブジェクト:問題の

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 
} 

このリストは、2つの場所に更新されます - 文字の作成、およびこれらの 'メリット' に専用の個別アクション。別のアクションでは、これらのオブジェクトのリストを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; 
} 

問題はキャラクター作成です。私は(、興味深いことに、デバッガによってキャッチされていないだけDbUpdateExceptionに包まれ、ストレートブラウザに行く)、次のエラーを取得し、このアクションを実行しようとするたびに

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

:アクションを作成します 。 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リストに追加するコードを削除した場合。 私は何を試しましたか?最初のDBから新しく作成Characterオブジェクトを検索に加えてAddOrUpdateCharacter()呼び出し

  • 上、後にリスト操作を移動

    • 私が考えた過渡するリポジトリを設定する代わりにStartup

    にスコープ(代わりにコントローラにCharacterオブジェクトを操作する)新しいリストを初期化し、

  • 上UpdateMerits()メソッドを使用してこのアクションを実行する別のものにリダイレクトすることができますが、概念的な観点からはこのコードはこのアクションに属します。もしあれば、根本的な問題は解決しません。 アプリケーションは現在localdb上で実行されていますが、標準SQL Server db上で実行されているデプロイ済みバージョンもあります。 私はEFでコレクションを扱ったのは今回が初めてではないので、ここで何が間違っているのかは完全にわかりません。

  • +2

    AddOrUpdateCharacterにコードを表示します。また、コントローラでリポジトリをインスタンス化する方法と、dbContextへの参照を取得する方法はありますか? – wllmsaccnt

    +0

    質問を更新しました。リポジトリとdbcontextは、ASP.NET Coreの依存性注入システムによってインスタンス化されるため、それぞれのコンストラクタで初期化されたプライベートフィールドです。私は 'ConfigureServices()'のコードも追加しました。 – Telvee32

    答えて

    0

    この例外は、接続が切断されたことを示しているようです。あなたはAzureまたは他のクラウドプロバイダを使用していますか?いずれにせよ、私はあなたがEFコアのconnection resiliency機能を試してみることをお勧めします。

    +0

    これはlocaldbインスタンス上にあります。デプロイされたバージョンはGearHostにありますが(明らかにAzureに基づいているようですが)、このコードはまだ公開されていません。 – Telvee32

    +0

    接続回復機能を試してみませんか? –

    +0

    それは実際に働いた、うわー、ありがとう。その場合、本当の疑問はなぜ接続が落とされたのでしょうか? – Telvee32

    関連する問題