【问题标题】:Error when serializing entity framework objects序列化实体框架对象时出错
【发布时间】:2019-09-06 21:15:38
【问题描述】:

背景:

我有一个 API,它使用两个表(令牌和区域)从数据库中检索数据。每个 Token 都有一个与 Area 对象相关的 AreaID。我首先使用实体​​框架数据库。

问题:

当我尝试查询数据库以获取 Token(应包含对区域的引用)时。我收到一个错误:

Error getting value from 'Area' on 'System.Data.Entity.DynamicProxies.Token_51B85DEDCE118919D07024535C24194E890BF0A8499689750190733A8008D739'."

代码:

以下是 EF 创建的模型:

public partial class Token
{
    public System.Guid ID { get; set; }
    public System.DateTime Expiry { get; set; }
    public System.Guid Reference { get; set; }
    public string IPAddress { get; set; }
    public string TokenValue { get; set; }
    public Nullable<System.Guid> Area_ID { get; set; }
    public virtual Area Area { get; set; }
}



public partial class Area
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]

    public Area()
    {
        this.Tokens = new HashSet<Token>();
    }
    public System.Guid ID { get; set; }
    public string Name { get; set; }
    public string UriPrefix { get; set; }
    public string Description { get; set; }
    public System.DateTime Created { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Token> Tokens { get; set; }
}

这是我查询数据库的地方(精简):

using (var dbContext = new APIEntities())
{
    try
    {
        tokenObject = dbContext.Tokens.Where(t => t.TokenValue == decryptedToken).FirstOrDefault(); 
        // the tokenObject is created but the Area property is null.
    } catch (Exception ex) {
        string message = ex.Message.ToString();
    }
}

下面是序列化 JSON 的方法:

 public HttpResponseMessage LogIntoAppWithToken()
    {
        string result = "";
        string jsonString = "failed to get JSON";
        string message = "";
        try
        {
            var re = Request;
            var headers = re.Headers;
            EncryptedToken encToken = new EncryptedToken();
            TokenChecker tokenChecker = new TokenChecker();
            encToken.tokenValue = "";

            if (headers.Contains("X-TOKEN"))
            {
                encToken.tokenValue = headers.GetValues("X-TOKEN").First();
            } 

            result = tokenChecker.IsTokenValid(encToken).ToString();
            Token retrievedToken = tokenChecker.GetTokenByTokenValue(encToken.tokenValue);
            jsonString = JsonConvert.SerializeObject(retrievedToken);
            // ERROR Here ^^

        } catch (Exception ex) {
            message = ex.Message.ToString();
        }
        return Request.CreateResponse(HttpStatusCode.OK, "Token is valid: " + result + ". " + " " + jsonString + " " + " Any error messages: " + message);
    }

我尝试过的:

创建 dbContext 时我使用过:

dbContext.Configuration.ProxyCreationEnabled = false;
dbContext.Configuration.LazyLoadingEnabled = false;

在 WebApiConfig 中:

        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
        config.Formatters.Remove(config.Formatters.XmlFormatter);

在 Global.asax 的 Application_start 中:

config.Formatters.JsonFormatter
    .SerializerSettings
    .ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

我什至尝试从 tokenObject 获取 AreaID 并查询数据库以“手动”获取区域,然后将此检索到的区域对象添加到 tokenObject(覆盖空版本):

Area areaObject = dbContext.Areas.Where(a => a.ID == tokenObject.Area_ID).FirstOrDefault();
tokenObject.Area = areaObject;

但这会导致自引用循环错误。 (这个想法更多的是用于测试而不是用作解决方案)。

我需要做什么才能检索包含一个区域作为其属性之一的令牌,然后序列化为 JSON 字符串?

编辑 1

在@ErikEJ 的建议下:

我注意到 Token 对象现在包含 Area 对象,但 Area 对象包含一个包含 Area 的 Token?这种情况一直在继续……

根据我的设置,令牌肯定包含区域,但区域不应该包含令牌?

【问题讨论】:

    标签: c# entity-framework asp.net-web-api


    【解决方案1】:

    经过大量搜索,我找到了另一个对我有用的answer

    只需将 [JsonIgnore] 属性添加到受影响的属性即可。对我来说区域模型:

        [JsonIgnore]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Token> Tokens { get; set; }
    

    【讨论】:

      【解决方案2】:

      使用包含:

       tokenObject = dbContext.Tokens
            .Where(t => t.TokenValue == decryptedToken)
            .Include(t => t.Area) 
            .FirstOrDefault();
      

      【讨论】:

      • 我已经尝试了您的建议并相应地编辑了问题。
      【解决方案3】:

      如果您不想序列化引用的实体,请使用以下选项之一。

      1. 使用 [JsonIgnore] 注释特定属性。
      2. 要禁用特定属性的延迟加载,请不要将其设为虚拟
      3. 为了避免所有实体的延迟加载,请将 LazyLoadingEnabled 设置为 false 在你的 bdContext 类中。

        public SchoolDBEntities(): base("name=SchoolDBEntities")
        {
            this.Configuration.LazyLoadingEnabled = false;
        }
        

        不用担心,您仍然可以通过调用 Include 方法来访问您引用的实体。 示例:-

             var list = context.Customers
            .Include(c => c.Invoices)    
            .ToList();
        

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-09
        • 2012-12-16
        • 2011-12-20
        • 1970-01-01
        • 1970-01-01
        • 2020-08-21
        • 2012-02-08
        相关资源
        最近更新 更多