servicestack,circular-reference,C#,Json.net,servicestack,Circular Reference" /> servicestack,circular-reference,C#,Json.net,servicestack,Circular Reference" />

C# 文本序列化循环引用

C# 文本序列化循环引用,c#,json.net,servicestack,circular-reference,C#,Json.net,servicestack,Circular Reference,我需要像这样序列化对象图: public class A { public B Link1 {get;set;} } public class B { public A Link2 {get;set;} } 因此,json只获得两个实例,但再次被正确反序列化。例如,使用元Id或类似的东西 我知道Json.NET中有一种方法,如本文所述:使用元ID ServiceStack.TextJson序列化程序中是否有类似的功能 否则,是否可以在ServiceStack中使用Json

我需要像这样序列化对象图:

public class A
{
     public B Link1 {get;set;}
}

public class B
{
     public A Link2 {get;set;}
}
因此,json只获得两个实例,但再次被正确反序列化。例如,使用元Id或类似的东西

我知道Json.NET中有一种方法,如本文所述:使用元ID

ServiceStack.Text
Json序列化程序中是否有类似的功能

否则,是否可以在
ServiceStack
中使用Json.NET,以及如何使用

编辑:

为了清楚起见,我要求引用实例,而不仅仅是同一类型。 例如:

[
    {
        "$id": "1",
        "BroId": 0,
        "Name": "John",
        "Bros": [
            {
                "$id": "2",
                "BroId": 0,
                "Name": "Jared",
                "Bros": [
                    {
                        "$ref": "1"
                    }
                ]
            }
        ]
    },
    {
        "$ref": "2"
    }
]
只有2个对象“真正”序列化,其余的对象使用
$ref
属性字段重用。 设想一个对象模型有一组子项。这些子项具有对其父对象的反向引用。例如,客户/订单。一个客户有多个订单,每个订单都有对其客户的引用。 现在想想如果序列化一个客户会发生什么

Customer
 -> Order
  -> Customer
   -> Order
    -> ...
您将得到与此站点名称相似的结果。;)

我非常喜欢ServiceStack的清晰性,不需要
KnownTypeAttribute
s等


我希望保持它的整洁,而不必在我的业务逻辑POCO中实现自定义加载程序/对象初始值设定项。

ServiceStack默认支持循环引用

为什么不先亲自尝试一下,在发布之前确认是否存在实际问题?这比提出一个新问题并要求其他人去做要省力

以你为例:

public class A
{
    public string Name { get; set; }
    public B Link1 { get; set; }
}

public class B
{
    public string Name { get; set; }
    public A Link2 { get; set; }
}

var dto = new A { 
   Name = "A1", 
   Link1 = new B { Name = "B1", Link2 = new A { Name = "A2" } } 
};
dto.ToJson().Print();
将打印JSON字符串:

{"Name":"A1","Link1":{"Name":"B1","Link2":{"Name":"A2"}}}
将其序列化为JSON并再次反序列化,如:

var fromJson = dto.ToJson().FromJson<A>();
fromJson.PrintDump();

我用另一种方法解决了这个问题这实际上是可行的,但在以后使用具有多个循环引用的更复杂的数据结构时可能会出现问题。但目前没有必要

我尝试将循环引用功能添加到
ServiceStack.Text
中,但没有找到起点。也许mythz能给我一个提示?这个特性应该非常简单

我需要这个特性来序列化我的数据模型,以完全支持
NHibernate
的合并功能

我按照mythz的建议忽略了带有
IgnoreDataMemberAttribute
的属性,这些属性会导致循环引用。 但这也需要在再次反序列化之后重新构建它们,以使合并功能正常工作

->这是解决方案,现在按照我的方法执行:

我从一个简单的原型开始测试,一个

客户
1->n
订单
1->n
订单详情

每个类都派生自实体类

public class Customer : Entity
{
    public virtual string Name { get; set; }
    public virtual string City { get; set; }
    public virtual IList<Order> Orders { get; set; }
}

public class Order : Entity
{
    public virtual DateTime OrderDate { get; set; }
    public virtual IList<OrderDetail> OrderDetails { get; set; }
    [IgnoreDataMember]
    public virtual Customer Customer { get; set; }
}

public class OrderDetail : Entity
{
    public virtual string ProductName { get; set; }
    public virtual int Amount { get; set; }
    [IgnoreDataMember]
    public virtual Order Order{ get; set; }
}
该代码目前不适用于1->1实体引用(目前还不需要),但我认为它可以很容易地扩展

现在,我可以在客户端使用POCO类模型,添加/更新/删除子对象,并将整个树发送回服务器
Nhibernate
非常聪明,可以确定哪个实体是新的/更新的/删除的。它还仅更新已更改的实体以及已更改的属性!如果订单被删除,它还会删除所有OrderDetails

这就是完整性的fluent nhibernate映射:

public class CustomerMap : ClassMap<Customer>
{
    public CustomerMap()
    {
        Schema("YOURSCHEMA");
        Table("CUSTOMER");
        Id(x => x.Id, "ID").GeneratedBy.Assigned();
        Map(x => x.Name, "NAM");
        Map(x => x.City, "CITY");
        HasMany(x => x.Orders)
            .KeyColumn("CUSTOMER_ID")
            .Not.LazyLoad()
            .Inverse()
            .Cascade.AllDeleteOrphan();


        DynamicUpdate();
    }
}

public class OrderMap : ClassMap<Order>
{
    public OrderMap()
    {
        Schema("YOURSCHEMA");
        Table("CUSTOMER_ORDER");
        Id(x => x.Id, "ID").GeneratedBy.Assigned();
        Map(x => x.OrderDate, "ORDER_DATE");
        HasMany(x => x.OrderDetails)
            .KeyColumn("ORDER_ID")
            .Not.LazyLoad()
            .Inverse()
            .Cascade.AllDeleteOrphan();

        References<Customer>(x => x.Customer, "CUSTOMER_ID");
        DynamicUpdate();
    }
}

public class OrderDetailMap : ClassMap<OrderDetail>
{
    public OrderDetailMap()
    {
        Schema("YOURSCHEMA");
        Table("ORDER_DETAIL");
        Id(x => x.Id, "ID").GeneratedBy.Assigned();
        Map(x => x.ProductName, "PRODUCT_NAME");
        Map(x => x.Amount, "AMOUNT");

        References<Order>(x => x.Order, "ORDER_ID");
        DynamicUpdate();
    }
}
公共类CustomerMap:ClassMap
{
公共客户映射()
{
模式(“你的模式”);
表(“客户”);
Id(x=>x.Id,“Id”).GeneratedBy.Assigned();
地图(x=>x.名称,“NAM”);
地图(x=>x.城市,“城市”);
HasMany(x=>x.Orders)
.KeyColumn(“客户ID”)
.Not.LazyLoad()
.Inverse()
.Cascade.AllDeleteOrphan();
DynamicUpdate();
}
}
公共类OrderMap:ClassMap
{
公共秩序地图()
{
模式(“你的模式”);
表(“客户订单”);
Id(x=>x.Id,“Id”).GeneratedBy.Assigned();
映射(x=>x.OrderDate,“订单日期”);
HasMany(x=>x.OrderDetails)
.KeyColumn(“订单ID”)
.Not.LazyLoad()
.Inverse()
.Cascade.AllDeleteOrphan();
参考资料(x=>x.客户,“客户ID”);
DynamicUpdate();
}
}
公共类OrderDetailMap:ClassMap
{
public OrderDetailMap()
{
模式(“你的模式”);
表(“订单详情”);
Id(x=>x.Id,“Id”).GeneratedBy.Assigned();
地图(x=>x.ProductName,“产品名称”);
Map(x=>x.金额,“金额”);
参考文献(x=>x.顺序,“顺序ID”);
DynamicUpdate();
}
}
DynamicCupDate()用于让nhibernate仅更新更改的属性。
现在只需使用ISession.Merge(customer)函数即可正确保存所有内容。

如果任何人需要能够使用循环序列化对象图,JSON.NET确实支持它:

new JsonSerializer
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects
};

您的示例dto没有使用循环引用-它对每个链接属性使用不同的对象。:-)同意。但我想这就是OP的要求。是的,这就是我的要求。
public class CustomerMap : ClassMap<Customer>
{
    public CustomerMap()
    {
        Schema("YOURSCHEMA");
        Table("CUSTOMER");
        Id(x => x.Id, "ID").GeneratedBy.Assigned();
        Map(x => x.Name, "NAM");
        Map(x => x.City, "CITY");
        HasMany(x => x.Orders)
            .KeyColumn("CUSTOMER_ID")
            .Not.LazyLoad()
            .Inverse()
            .Cascade.AllDeleteOrphan();


        DynamicUpdate();
    }
}

public class OrderMap : ClassMap<Order>
{
    public OrderMap()
    {
        Schema("YOURSCHEMA");
        Table("CUSTOMER_ORDER");
        Id(x => x.Id, "ID").GeneratedBy.Assigned();
        Map(x => x.OrderDate, "ORDER_DATE");
        HasMany(x => x.OrderDetails)
            .KeyColumn("ORDER_ID")
            .Not.LazyLoad()
            .Inverse()
            .Cascade.AllDeleteOrphan();

        References<Customer>(x => x.Customer, "CUSTOMER_ID");
        DynamicUpdate();
    }
}

public class OrderDetailMap : ClassMap<OrderDetail>
{
    public OrderDetailMap()
    {
        Schema("YOURSCHEMA");
        Table("ORDER_DETAIL");
        Id(x => x.Id, "ID").GeneratedBy.Assigned();
        Map(x => x.ProductName, "PRODUCT_NAME");
        Map(x => x.Amount, "AMOUNT");

        References<Order>(x => x.Order, "ORDER_ID");
        DynamicUpdate();
    }
}
new JsonSerializer
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects
};