【问题标题】:Entity Framework code-first working with local DB, but errors when deployed to Azure实体框架代码优先使用本地数据库,但部署到 Azure 时出错
【发布时间】:2014-03-21 21:12:40
【问题描述】:

我开发了一个使用 Asp.Net Web API 的项目,遵循 Entity Framework code-first 方法。

我已经在 Visual Studio 2013 中使用本地数据库在本地机器上对其进行了测试,它可以正常工作。

当我替换连接字符串并将数据库部署到 Azure 时,问题就出现了。我可以执行一些查询,但不能执行其他查询。

例如,如果我在浏览器中输入 http://my-site/api/users/1 我会得到预期的结果。但是查询http://my-site/api/users/ 向我返回了与Json 序列化相关的错误:

{ "$id" : "1",
  "ExceptionMessage" : "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.",
  "ExceptionType" : "System.InvalidOperationException",
  "InnerException" : { "$id" : "2",
      "ExceptionMessage" : "Error getting value from 'Devices' on 'System.Data.Entity.DynamicProxies.User_50420314CCDC05AAF3288A574C1CBB8436C09BAEF7539C2795445FCBA161AC99'.",
      "ExceptionType" : "Newtonsoft.Json.JsonSerializationException",
      "InnerException" : { "$id" : "3",
          "ExceptionMessage" : "An error occurred while executing the command definition. See the inner exception for details.",
          "ExceptionType" : "System.Data.Entity.Core.EntityCommandExecutionException",
          "InnerException" : { "$id" : "4",
              "ExceptionMessage" : "There is already an open DataReader associated with this Command which must be closed first.",
              "ExceptionType" : "System.InvalidOperationException",
              "Message" : "An error has occurred.",
              "StackTrace" : "   at System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command)\r\n   at System.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String method, SqlCommand command)\r\n   at System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async)\r\n   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)\r\n   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)\r\n   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)\r\n   at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)\r\n   at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)\r\n   at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<>c__DisplayClassb.<Reader>b__8()\r\n   at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TInterceptionContext,TResult](Func`1 operation, TInterceptionContext interceptionContext, Action`1 executing, Action`1 executed)\r\n   at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)\r\n   at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior behavior)\r\n   at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)\r\n   at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)"
            },
          "Message" : "An error has occurred.",
          "StackTrace" : "   at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)\r\n   at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute[TResultType](ObjectContext context, ObjectParameterCollection parameterValues)\r\n   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClassb.<GetResults>b__a()\r\n   at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)\r\n   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClassb.<GetResults>b__9()\r\n   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)\r\n   at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)\r\n   at System.Data.Entity.Core.Objects.ObjectQuery`1.Execute(MergeOption mergeOption)\r\n   at System.Data.Entity.Core.Objects.DataClasses.EntityCollection`1.Load(List`1 collection, MergeOption mergeOption)\r\n   at System.Data.Entity.Core.Objects.DataClasses.EntityCollection`1.Load(MergeOption mergeOption)\r\n   at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.Load()\r\n   at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.DeferredLoad()\r\n   at System.Data.Entity.Core.Objects.Internal.LazyLoadBehavior.LoadProperty[TItem](TItem propertyValue, String relationshipName, String targetRoleName, Boolean mustBeNull, Object wrapperObject)\r\n   at System.Data.Entity.Core.Objects.Internal.LazyLoadBehavior.<>c__DisplayClass7`2.<GetInterceptorDelegate>b__1(TProxy proxy, TItem item)\r\n   at System.Data.Entity.DynamicProxies.User_50420314CCDC05AAF3288A574C1CBB8436C09BAEF7539C2795445FCBA161AC99.get_Devices()\r\n   at GetDevices(Object )\r\n   at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)"
        },
      "Message" : "An error has occurred.",
      "StackTrace" : "   at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)\r\n   at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)\r\n   at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)\r\n   at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)\r\n   at System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)\r\n   at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content)\r\n   at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n   at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__19.MoveNext()"
    },
  "Message" : "An error has occurred.",
  "StackTrace" : null
}

这个问题真的让我很恼火,因为正如我所提到的,使用本地数据库可以正常工作。本地生成的数据库和 Azure 中生成的数据库似乎相同。所以,我猜不出问题出在哪里。

【问题讨论】:

  • 两个数据库中的数据是否确认为等价的?由于数据不同,这可能只是一个问题。另外,您能否发布用户和设备实体的相关代码,以及流畅的 API 配置(如果有)?
  • 我现在没有代码,但User 有一个Devices 类型为ICollection&lt;Device&gt; 的属性。 Device 也有 User 类型的属性。即每个设备都有一个用户,而一个用户可以拥有许多设备。

标签: asp.net entity-framework azure ef-code-first azure-sql-database


【解决方案1】:

答案就是错误消息告诉您的内容。它无法将实体框架代理序列化为 JSON。您应该映射到 POCO 类并返回它们:

//poco
    public class PersonPoco
    {
       public string FirstName {get;set;}
       public string LastName {get;set;}
    }

//控制器

public IEnumerable<PersonPoco> Get()
{
    var person = _personRepository.FindAll();

    person.Select(x=> new PersonPoco() {
     FirstName = x.f_name,
     LastName = x.l_name
    }).ToList();
}

你可以使用 AutoMapper 来做这个转换,你可以创建扩展方法来做这个转换。无论如何,这只是一个样本。

【讨论】:

  • 我明天会检查这是否是问题所在。但是,为什么当我使用本地数据库时它会起作用?
  • 好问题。我几乎可以肯定它在本地也不会工作。
  • 这就是为什么我想知道它是否与数据有关。如果查询在 localdb 上没有返回数据,则不会出现序列化错误。顺便说一句,另一种解决方案是关闭动态代理并使用显式 .Include 语句。
【解决方案2】:

将 .ToArray() 添加到我从 GetAll() 方法返回的结果中解决了问题:

    public IEnumerable<TEntity> GetAll()
    {
        return _dbContext.Set<TEntity>().ToArray();
    }

但是,我仍然想知道为什么它使用本地数据库而不是部署到 Azure 的数据库。

添加MultipleActiveResultSets=True 也解决了我的问题。但由于我真的不知道启用该功能需要什么,所以我选择了第一个选项。

【讨论】:

  • 是的。 .ToArray() , .ToList(), .Single() ,所有这些都会返回对象。您不能返回的是实体框架代理。我建议你映射到 POCO 以避免这种情况,但返回这种方式也可以。
  • MultipleActiveResultSets 在您有正在延迟加载的子对象时是必需的。这允许 EF 打开一个结果集(为您的父对象)并打开新结果集以获取子对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-23
  • 1970-01-01
  • 2014-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多