【问题标题】:Adding Entity with child entities to Redis server resulting System.StackOverflowException将具有子实体的实体添加到 Redis 服务器导致 System.StackOverflowException
【发布时间】:2014-02-27 17:47:32
【问题描述】:

我正在使用 EF6 和 Database First 开发 ASP.NET MVC 项目。我正在尝试使用Redis server 来缓存常用对象。

但我在保存相关实体(父子)时遇到问题。例如下面的AuthorAuthor_Book 类是父子类并且相互引用(RDBMS 中的外键约束)

public partial class Author
{
    public int Id { get; set; }
    public string Name { get; set; }  
    public virtual ICollection<Author_Book> Author_Book { get; set; }
}

public partial class Author_Book
{
    public int Id { get; set; }
    public int AuthorId { get; set; }
    public string Title { get; set; }
    public virtual Author Author { get; set; }
}

public partial class Customer
{
    public int ID { get; set; }
    public string CustomerName { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
}

查询并尝试将查询结果存储到Redis server,如下所示

using (EFTestContext db = new EFTestContext())
{
    var data = db.Authors.ToList();
    redisClient.Set<List<Author>>("author", data);
}

redisClient.Set.. 的上方产生以下Exception

An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll

但是,如果我将客户实体(没有子实体)存储到 Redis server 中,它可以正常工作

using (EFTestContext db = new EFTestContext())
{
    var customers = db.Customers.ToList();
    redisClient.Set<List<Customer>>("customers", customers);
}

所以我的问题是如何将完整的实体(带子实体)存储到 redis 服务器中?

【问题讨论】:

  • 试试 db.Configuration.ProxyCreationEnabled = false;
  • Author 有一个Author_Book 的集合并且每个Author_Book 也引用Author 是否有问题?我不知道 redis 客户端是如何工作的,但它可能正在尝试序列化对象图,然后遇到堆栈溢出异常。
  • @Daniel 我也认为这可能是由于该循环引用。但它是从 EF 数据库优先生成的。如果我删除循环引用,EF 开始抱怨。
  • @OferZelig 非常感谢!该链接对我很有帮助。

标签: c# asp.net-mvc entity-framework redis


【解决方案1】:

我遵循[DataContract] / [DataMember] 方法(正如@oferzelig 在评论中提到的那样)。它工作正常,不再引发该异常。我在这里对其进行描述,以便对其他人有所帮助。

EF Database-first 默认不添加[DataContract] / [DataMember]属性,我们需要修改T4模板。我在模型模板Model1.tt 中做了以下修改。

在行前添加[DataContract]属性

<#=codeStringGenerator.EntityClassOpening(entity)#>

现在看起来像

[DataContract]
<#=codeStringGenerator.EntityClassOpening(entity)#>

在行前添加[DataMember]属性

<#=codeStringGenerator.Property(edmProperty)#>

看起来像

[DataMember]
<#=codeStringGenerator.Property(edmProperty)#>

我们还需要为一对多关系生成[DataMember] 属性(例如public virtual ICollection&lt;Author_Book&gt; Author_Book { get; set; }),但NOT 用于一对一(例如public virtual Author Author { get; set; }) .为了实现它,我在CodeStringGenerator 类中添加了一个新功能

public string NavigationProperty_NeedDataMember(NavigationProperty navProp)
{
    return string.Format(
        CultureInfo.InvariantCulture,
        "{0}",
        navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("[DataMember]") : ""
        );
}

并在该行之前调用它

<#=codeStringGenerator.NavigationProperty(navigationProperty)#>

如下

<#=codeStringGenerator.NavigationProperty_NeedDataMember(navigationProperty)#>
<#=codeStringGenerator.NavigationProperty(navigationProperty)#>

最后修改UsingDirectives过程添加System.Runtime.Serialization,如下

public string UsingDirectives(bool inHeader, bool includeCollections = true)
{
    return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion())
        ? string.Format(
            CultureInfo.InvariantCulture,
            "{0}using System;{1}" +
            "{2}" +
            "{3}",
            inHeader ? Environment.NewLine : "",
            includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "",
            includeCollections ? (Environment.NewLine + "using System.Runtime.Serialization;") : "",
            inHeader ? "" : Environment.NewLine)
        : "";
}

就是这样。

现在它正在生成以下类,我无需在每次更新后手动编辑类。

[DataContract]
public partial class Author
{
    [DataMember]
    public int Id { get; set; }
    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public virtual ICollection<Author_Book> Author_Book { get; set; }
}

[DataContract]
public partial class Author_Book
{
    [DataMember]
    public int Id { get; set; }
    [DataMember]
    public int AuthorId { get; set; }
    [DataMember]
    public string Title { get; set; }


    public virtual Author Author { get; set; }
}

希望对其他人有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多