c# - Azure 应用服务(移动)上的数据库上下文失败

标签 c# asp.net entity-framework azure-api-apps azure-mobile-services

我有一个在 Azure App Service - Mobile 上运行的 Controller 。跟踪显示以下代码运行良好,直到 db.SaveChanges() 失败。

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

来自应用服务诊断的堆栈跟踪(不幸的是我不明白)给出:

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

还有

我将检查所有设置以确保根据 this answer on stackoverflow 不得为 null 的字段为 null .

测试以上内容

异常隐藏了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; }
}

最佳答案

EF 中不支持自动生成字符串主键。这就是您应该手动分配主键的原因。

您可以使用构造函数初始化IdCreatedDateUpdatedDate

    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 方法。当您修改实体时,此方法将自动更改更新日期。

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

编辑:第一个解决方案是通用解决方案,未与任何库一起使用。

EntityData你需要序列化。当移动客户端和后端服务器试图相互通信时,这个类将帮助你。例如,移动客户端不支持导航属性,但后端服务器支持。当您序列化实体数据时,它会为您隐藏这些属性。

如果您为此应用设计数据库。关注这个document .

首先:您应该使用库中的 EntityData 类。您的模型应该继承自它而不是您的 EntityData 类。

第二:你的上下文应该有这个代码来覆盖模型创建。你需要这个来自动更新 created/updated 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()));
        }

如果您使用已经存在的数据库,请遵循此 document .

关于c# - Azure 应用服务(移动)上的数据库上下文失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36483461/

相关文章:

c# - 从 C# 中的 PL/SQL 匿名 block 返回游标

c# - 是否可以使用当前的 Windows 用户凭据调用 c# WebService?

asp.net - 我如何摆脱未声明的 __o ?

c# - DbEntityValidationException - 必填字段为空

mysql - 向远程 MySql 服务器添加数据时发生错误

c# - 有什么方法可以更快地在 Canvas 上渲染大量移动对象(C# w/WPF)

c# - 在 C# 中解析 Json rest api 响应

asp.net - VS2010不发布特定的文件夹/文件

c# - 正则表达式模式问题

c# - Entity Framework - 错误地执行 2 个选择语句而不是连接