将具有子实体的实体添加到Redis服务器,从而导致System.StackOverflowException

时间:2014-02-27 17:47:33

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

我正在使用带有Database First的EF6开发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

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

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

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

1 个答案:

答案 0 :(得分:1)

我遵循[DataContract] / [DataMember]方法(正如评论中提到的@oferzelig)。它工作正常,不再提出异常。我在这里描述它可以帮助其他人。

EF数据库 - 默认情况下不添加[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<Author_Book> Author_Book { get; set; }),但 NOT 为一对一生成(例如{{ 1}}问题)。为了实现它,我在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)
        : "";
}

希望它会帮助别人。