5

私はAzure App Service - Mobileでコントローラを実行しています。トレースは、db.SaveChanges()が失敗するまで、以下のコードが正常に実行されることを示しています。azureアプリサービス(モバイル)のDbコンテキストが失敗する

var telemetry = new Microsoft.ApplicationInsights.TelemetryClient(); 
telemetry.TrackTrace("Create User"); 
using (BCMobileAppContext db = new BCMobileAppContext()) 
{ 
    string Username_NoSpaces = username.Username.Replace(" ", ""); 
    var user = db.Users.FirstOrDefault(u => u.Username_NoSpaces == Username_NoSpaces || u.MicrosoftToken == this.User.Identity.Name); 
    telemetry.TrackTrace("1"); 
    if (user == null && !Username_NoSpaces.Contains(",")) 
    { 
      telemetry.TrackTrace("2"); 
      DateTime now = DateTime.UtcNow; 
      telemetry.TrackTrace("3"); 
      string username_noSpaces = username.Username.Replace(" ", ""); 
      DataObjects.User userItem = new DataObjects.User() { Created = now, UserId = this.User.Identity.Name, MicrosoftToken = this.User.Identity.Name, Username_NoSpaces = username_noSpaces, Update = now, Username = username.Username, Gold = 1, Level = 1, Title = "Sir", InGameCrest = "", ReceiveNotifications = true }; 
      telemetry.TrackTrace("4"); 
      UserDTO returnObject1 = new UserDTO() { Created = userItem.Created, isCreated = true, MicrosoftId = userItem.MicrosoftToken, Username = userItem.Username }; 
      telemetry.TrackTrace("5"); 
      db.Users.Add(userItem); 
      telemetry.TrackTrace("6"); 
      db.SaveChanges();   //Trace and code fails 
      telemetry.TrackTrace("7"); 
      UserDTO returnObject = new UserDTO() { Created = userItem.Created, isCreated = true, MicrosoftId = userItem.MicrosoftToken, Username = userItem.Username }; 
      telemetry.TrackTrace("8"); 
      return Ok(returnObject); 
     } 
} 

appserviceの診断からのスタックトレースは、(私は残念ながら分かりません)与える:

2016-04-07T17:29:19 PID[5008] Error  Operation=ReflectedHttpActionDescriptor.ExecuteAsync, Exception=System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. 
    at System.Data.Entity.Internal.InternalContext.SaveChanges() 
    at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() 
    at System.Data.Entity.DbContext.SaveChanges() 
    at BCMobileAppService.Controllers.Test2Controller.Post(UserDTO username) in C:\Users\johann\Desktop\BCMobileApp_Runtime\BCMobileAppService\Controllers\TestController.cs:line 78 
    at lambda_method(Closure , Object , Object[]) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary 2 arguments, CancellationToken cancellationToken) 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 
2016-04-07T17:29:19 PID[5008] Error  Operation=ApiControllerActionInvoker.InvokeActionAsync, Exception=System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. 
    at System.Data.Entity.Internal.InternalContext.SaveChanges() 
    at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() 
    at System.Data.Entity.DbContext.SaveChanges() 
    at BCMobileAppService.Controllers.Test2Controller.Post(UserDTO username) in C:\Users\johann\Desktop\BCMobileApp_Runtime\BCMobileAppService\Controllers\TestController.cs:line 78 
    at lambda_method(Closure , Object , Object[]) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary 2 arguments, CancellationToken cancellationToken) 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 
2016-04-07T17:29:19 PID[5008] Error  Operation=Test2Controller.ExecuteAsync, Exception=System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. 
    at System.Data.Entity.Internal.InternalContext.SaveChanges() 
    at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() 
    at System.Data.Entity.DbContext.SaveChanges() 
    at BCMobileAppService.Controllers.Test2Controller.Post(UserDTO username) in C:\Users\johann\Desktop\BCMobileApp_Runtime\BCMobileAppService\Controllers\TestController.cs:line 78 
    at lambda_method(Closure , Object , Object[]) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.< >c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary 2 arguments, CancellationToken cancellationToken) 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.Tracers.HttpControllerTracer.<ExecuteAsyncCore>d__5.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 

更新

だから私はしようとしますthis、より詳細なエラーメッセージを表示します:

catch (DbEntityValidationException dbEx) 
{ 
foreach (var validationErrors in dbEx.EntityValidationErrors) 
{ 
    foreach (var validationError in validationErrors.ValidationErrors) 
    { 
     Trace.TraceInformation("Property: {0} Error: {1}", 
           validationError.PropertyName, 
           validationError.ErrorMessage); 
    } 
} 
} 

また

私はnullあってはならない分野がthis answer on stackoverflowに応じとしてnullであることを保証するために、すべての設定を通過します。

テスト例外はIdフィールドが必要であることを隠し

上記は、例外です。

Idは、EntityDatahere on msdnと記載)を使用しています。 MobileServiceでの私の使用は、db.SaveChanges()に失敗した行を実行したときにIdが作成されたことでした。誰かがこれを明確にすることはできますか?

public abstract class EntityData : ITableData 
{ 
    protected EntityData(); 

    [Index(IsClustered = true)] 
    [TableColumn(TableColumnType.CreatedAt)] 
    public DateTimeOffset? CreatedAt { get; set; } 
    [TableColumn(TableColumnType.Deleted)] 
    public bool Deleted { get; set; } 
    [TableColumn(TableColumnType.Id)] 
    public string Id { get; set; } 
    [TableColumn(TableColumnType.UpdatedAt)] 
    public DateTimeOffset? UpdatedAt { get; set; } 
    [TableColumn(TableColumnType.Version)] 
    public byte[] Version { get; set; } 
} 
+0

上記の設定を行ってもエラーが発生しましたか? –

+0

@RamiSarieddine私は今すべてをテストし、質問への更新を書きました。それは 'Exception'を与えるのは' EntityData'の 'Id'フィールドです。以前の研究から、実行時に失敗する行である 'db.SaveChanges()'を実行したときに作成されたことを理解しました。なぜこれが分かっていますか?以前は 'EntityData'を使用していませんでしたが、自動的に更新される' CreatedAt'と 'UpdatedAt'カラムのためにしたいと思いますか? – JTIM

+0

@AlexanderDerckいいえ、あなたから推測します: 'EntityData'を継承する私のクラスは、' [DatabaseGenerated(DatabaseGeneratedOption.Identity)]変数を持つべきです。 public string Id {get; set;; '' EntityData'の型と互換性があるか? – JTIM

答えて

3

EF内の文字列の主キーのサポートを生成する一切のオートはありません: クラスには、次のようになります。そのため、主キーを手動で割り当てる必要があります。

コンストラクタでId,CreatedDateおよびUpdatedDateを初期化できます。

public abstract class EntityData : ITableData 
    { 
    //Change the constructor to initilaize required filled with meaningful data. 
     protected EntityData() 
     { 
      Id=Guid.NewGuid().ToString(); 
      CreatedDate=DateTime.UtcNow; 
      UpdatedDate=DateTime.UtcNow; 
     } 

     [Index(IsClustered = true)] 
     [TableColumn(TableColumnType.CreatedAt)] 
     public DateTimeOffset? CreatedAt { get; set; } 
     [TableColumn(TableColumnType.Deleted)] 
     public bool Deleted { get; set; } 
     [TableColumn(TableColumnType.Id)] 
     public string Id { get; set; } 
     [TableColumn(TableColumnType.UpdatedAt)] 
     public DateTimeOffset? UpdatedAt { get; set; } 
     [TableColumn(TableColumnType.Version)] 
     public byte[] Version { get; set; } 
    } 

あなたのコンテキストでsavechangesメソッドを上書きできます。エンティティを変更すると、このメソッドはupdateddateを自動的に変更します。

public override int SaveChanges() 
    { 
     //Get Modified Entities 
     var modifiedEntries = ChangeTracker.Entries() 
      .Where(x => x.Entity is ITableData 
       && (x.State == EntityState.EntityState.Modified)); 
     foreach (var entry in modifiedEntries) 
     { 
      var entity = entry.Entity as ITableData; 
      //Modify updateddate 
      if (entity != null) 
      { 
       entity.UpdatedDate = DateTime.UtcNow; 
      } 
     } 
     return base.SaveChanges(); 
    } 

編集:最初のソリューションは、あらゆるライブラリとrealetedされていない一般的な解決策でした。

EntityDataセイラゼーションに必要です。モバイルクライアントとバックエンドサーバーが互いに通信しようとすると、このクラスが役立ちます。たとえば、モバイルクライアントはナビゲーションプロパティをサポートしていませんが、バックエンドサーバーはサポートしています。エンティティデータを直列化すると、これらのプロパティが非表示になります。

このアプリケーションのデータベースを設計する場合は、これに続いてdocument

最初に:EntityDataライブラリの中にあるクラスを使用する必要があります。あなたのモデルは、あなたのEntityDataクラスではなく、それから継承する必要があります。

2番目:オーバーライドモデルの作成時にコンテキストにこのコードが必要です。あなたは作成/更新されたatとIdの自動更新に必要です(これはあなたの質問に対する答えです)。

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
      string schema = ServiceSettingsDictionary.GetSchemaName(); 
      if (!string.IsNullOrEmpty(schema)) 
      { 
       modelBuilder.HasDefaultSchema(schema); 
      } 

      modelBuilder.Conventions.Add(
       new AttributeToColumnAnnotationConvention<TableColumnAttribute, string>(
        "ServiceTableColumn", (property, attributes) => attributes.Single().ColumnType.ToString())); 
     } 

すでに存在するデータベースを使用する場合は、このに従ってください。

+0

さて、これは関数をオーバーライドするのが普通の習慣ですか?もしそうなら、私はこのソリューションをどこに置くべきでしょうか? – JTIM

+1

'BCMobileAppContext' –

+0

さて、私は今夜これを試してみましょう! – JTIM

関連する問題