5

我有一個在Azure應用服務 - 移動版上運行的控制器。跟蹤顯示下面的代碼運行良好,直到db.SaveChanges()失敗。天青應用服務(移動)上的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); 
    } 
} 
} 

此外

我將通過所有的設置,以確保一個必須不能nullnull爲根據this answer on stackoverflow

測試上述

例外隱藏該Id字段是必需的,是個例外。

我使用的數據庫使用EntityData(描述here on msdn),其中Id來自。我在MobileService上使用的是Id是在我執行該行時創建的,而該行失敗了db.SaveChanges()。有人可以澄清這一點嗎? 類看起來是這樣的:

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我現在已經測試了一切,並且寫了一個更新的問題,它是來自'EntityData'的'Id'字段,它給出'Exception'。我從以前的工作中瞭解到,這是在執行'db.SaveChanges()'時創建的,它是執行失敗的行。你知道這是爲什麼嗎?我之前沒有使用'EntityData',但是想要這樣做,因爲'CreatedAt'和'UpdatedAt'列會自動更新? – JTIM

+0

@AlexanderDerck沒有,所以從你推斷:我的班級,從'EntityData'繼承應該有一個變量'[DatabaseGenerated(DatabaseGeneratedOption.Identity) 公共字符串ID {獲得;設置;}'以與來自'EntityData'的類型兼容,或者? – JTIM

回答

3

沒有自動生成在EF字符串主鍵的支持。這就是爲什麼你應該手動分配你的主鍵。

您可以用構造函數初始化Id,CreatedDateUpdatedDate

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您需要進行系列化。當移動客戶端和後端服務器嘗試彼此通信時,此類將幫助您。例如,移動客戶端不支持導航屬性,但後端服務器不支持。當你連續化entitydata時,它會爲你隱藏這些屬性。

如果你爲這個應用程序設計你的數據庫。按照這個document

第一:你應該使用EntityData類庫裏面的類。你的模型應該繼承它而不是你的EntityData類。

二:你的背景下應該有覆蓋模型創建此代碼。你需要這個自動更新創建/更新和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())); 
     } 

如果您使用的數據庫已存在,請遵循此document

+0

好的,所以這是正常的做法來覆蓋功能?如果是這樣的話,我應該在控制器中放置這個還是? – JTIM

+1

在'BCMobileAppContext' –

+0

好吧,今晚我會試試這個! – JTIM