[英]Self Reference when serializing nested Object
I want to store a snapshot of a nested model in my database as sort of a change history.我想在我的数据库中存储嵌套 model 的快照作为更改历史记录。 Therefore I made a model that serializes the whole object into a JSON string for easier storage.
因此,我制作了一个 model 将整个 object 序列化为 JSON 字符串以便于存储。
Simplified Data
class I want to store:简化
Data
class 我要存储:
public class Data
{
public int Id { get; set; }
public string SomeInfo { get; set; }
public virtual ICollection<DataObject> DataObject { get; set; }
}
The DataObject
for the collection inside Data
: Data
内部集合的DataObject
:
public class DataObject
{
public int Id { get; set; }
public string SomeMoreInfo { get; set; }
public int DataId { get; set; }
public virtual Data Data { get; set; }
}
My snapshot class looks something like this:我的快照 class 看起来像这样:
public class DataHistory
{
public int Id { get; set; }
private string _Data;
[NotMapped]
public Data Data
{
get { return _Data == null ? null : JsonConvert.DeserializeObject<Data>(_Data); }
set { _Data = JsonConvert.SerializeObject(value , Formatting.Indented,
new JsonSerializerSettings {
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
PreserveReferencesHandling = PreserveReferencesHandling.None
});
}
}
}
Inside my controller I do:在我的 controller 里面我做:
var data = await _repo.GetData(id);
var historyEntry = new DataHistory();
historyEntry.Data= data;
_repo.Add(historyEntry);
GetData()
method inside the repository:存储库中的
GetData()
方法:
public async Task<Data> GetData(int id)
{
return await _context.Data
.Include(d => d.DataObject)
.FirstOrDefaultAsync(d => d.Id == id);
}
The problem is when I try to serialize one Data
entry I get a self reference inside the DataObject
so it includes the Data
object again and also the DataObjects
.问题是当我尝试序列化一个
Data
条目时,我在DataObject
中获得了一个自我引用,因此它再次包含Data
object 以及DataObjects
。 Even with ReferenceLoopHandling.Ignore
the produced JSON looks something like this:即使使用
ReferenceLoopHandling.Ignore
生成的 JSON 看起来像这样:
{
"Id": 1051,
"SomeInfo": "asdasd",
"DataObject": [
{
"Id": 121,
"SomeMoreInfo": "asdasd",
"Data": {
"Id": 1051,
"SomeInfo": "asdasd",
"DataObject": [
{
"Id": 122,
"SomeMoreInfo": "asdasd",
"DataId": 1051
}
]
}
},
{
"Id": 122,
"SomeMoreInfo": "asdasd",
"Data": {
"Id": 1051,
"SomeInfo": "asdasd",
"DataObject": [
{
"Id": 121,
"SomeMoreInfo": "asdasd",
"DataId": 1051
}
]
}
}
]
}
EDIT: Expected output would be something like this:编辑:预计 output 将是这样的:
{
"Id": 1051,
"SomeInfo": "Data",
"DataObject": [
{
"Id": 121,
"SomeMoreInfo": "DataObject1"
"DataId": 1051
},
{
"Id": 122,
"SomeMoreInfo": "DataObject2"
"DataId": 1051
}
]
}
How can I stop it from including Data
a second time without using DTOs?如何在不使用 DTO 的情况下阻止它再次包含
Data
?
EDIT:编辑:
If I try it without Entity Framework, ReferenceLoopHandling.None
works as expected.如果我在没有实体框架的情况下尝试它,
ReferenceLoopHandling.None
会按预期工作。 See Dotnet Fiddle https://dotnetfiddle.net/bmAoAW .请参阅 Dotnet Fiddle https://dotnetfiddle.net/bmAoAW 。 So there seems to be a problem with my EF Core configuration or something.
所以我的 EF Core 配置似乎有问题。
You said in the comments that effectively you want to DataObject.Data
property to be ignored whenever you are serializing Data
from within DataHistory
.您在评论中说,当您从
DataHistory
中序列化Data
时,您实际上希望忽略DataObject.Data
属性。 You can do this by using a custom ContractResolver
to ignore the property programmatically.您可以通过使用自定义
ContractResolver
以编程方式忽略该属性来执行此操作。
Here is the code you would need for the resolver:这是解析器所需的代码:
public class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
if (prop.DeclaringType == typeof(DataObject) && prop.PropertyName == nameof(DataObject.Data))
{
prop.Ignored = true;
}
return prop;
}
}
Then apply it within the JsonSerializerSettings
in DataHistory.Data
:然后在
JsonSerializerSettings
的DataHistory.Data
中应用它:
set { _Data = JsonConvert.SerializeObject(value , Formatting.Indented,
new JsonSerializerSettings {
ContractResolver = new CustomResolver(),
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
PreserveReferencesHandling = PreserveReferencesHandling.None
});
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.