在ASP.NET Web API 2中,如何在JSON序列化中保留对象引用?

时间:2018-07-18 07:40:04

标签: c# asp.net python-2.7 asp.net-web-api2

我有一个使用ASP.NET Web API 2和Entity Framework 6创建的REST API。我想序列化/反序列化对象并保留对其他对象的引用。

我已经在ASP.NET中定义了Tag模型类,该类还具有通过脚手架生成的香草控制器类:

// C#
// Tag.cs
public class Tag
{
    public int ID { get; set; }
    public string Value { get; set; }
    public Tag Parent { get; set; } // I know this can't be circular 
}

...

// Context.cs
...
public DbSet<Tag> Tag { get; set; }
...
modelBuilder.Entity<Tag>().HasOptional(_ => _.Parent);

我正在使用requestsjsonPickle模块在​​Python中创建客户端。我有一个在Python中定义的等效类:

# Python 
class Tag():
    def __init__(self, jSrc=None):
        #super(DBEntity,self).__init__()        
        self.ID = 0        
        self.Value = ""
        self.Parent = None

        if(jSrc != None):
             self.__dict__ = jsonpickle.decode(jSrc)

以下Python代码可以正常工作,以便在“标签”表中创建标签条目:

newTag = Tag()
newTag.Value = "Parent"
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
r = requests.post("http://server/api/Tags", data=jsonpickle.encode(newTag), headers=headers)


# ID | Value  | Parent_ID
# 1  | Parent | -

但是当我将父标签分配给具有正确ID设置的标签对象时,将创建2个新的Tag条目,而不是使用父ID引用:

# Get Tag
rg = requests.get("http://server/api/Tags/1")
parentTag = Tag(rg.text)

# Create new Tag with Parent reference
newTag = Tag()
newTag.Value = "Child"
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
r = requests.post("http://server/api/Tags", data=jsonpickle.encode(newTag), headers=headers)

# ID | Value  | Parent_ID
# 1  | Parent | -
# 2  | Parent | - << This should net be created
# 3  | Child  | 2 << This should be 1

数据库现在包含2个“父”标签,但是“子”标签的Parent_ID字段已正确设置为新创建的不正确的“父”标签。

我如何告诉ASP.NET系统查找父标记的ID并保留对原始标记的引用,而不仅仅是将父属性反序列化为新的标记条目?

1 个答案:

答案 0 :(得分:0)

每个对ASP.NET的请求都应获得一个新的DbContext。这意味着,每次需要更新数据库时,都应检索要更新的记录,然后在SaveChanges之前对其进行更新。

如果仅反序列化一个对象并保存更改,它将(如您所见)在数据库中创建新记录。

我建议您实现标准的3层机制,在API / Controller中使用视图模型,在业务层中使用DTO,在数据库层中使用实体(当前具有实体)。

简单(但我会建议错误)的修复程序将在您的控制器中执行以下操作:

public void MyAPI(ApiViewModel vm) 
{
 var entity = _dbContext.Find(tag.Id);
 entity.Value = vm.Value;
 _dbContext.SaveChanges();
 return Ok();
}