EF 和 [JsonIgnore]:为什么我在使用现有类型时得到一个空字典,但在使用匿名类型时却没有?

EF and [JsonIgnore]: Why do I get an empty dictionary when using an existing type, but not when using an anonymous type?

问题

使用匿名类型时有效,但使用与匿名类型相同的类型 ClientGroupView 时无效。为什么?

我怀疑这与 [JsonIgnore] 属性有关 - 它以某种方式与 类型的对象 相关,但与 匿名对象[无关] =81=].

背景

我在 ClientsClientGroups 和一个 return 的控制器之间建立了多对多关系给定客户的组。

控制器方法 returns Json 带有一个空字典,当我使用 类型的对象时 ,但如果我使用 匿名对象,那么它return就是预期的Json。我在 .NET 5 和 .Net 6 上得到了相同的结果。

使用匿名对象时,Json returned 是:

[{
    "group":{ "clientGroupId":1, "groupName":"ClientGroup1" },
    "permissions":{ "rClientGroupClientId":1, "clientGroupId":1, "clientId":1 }
}]

当使用 ClientGroupView 类型的对象(不包含任何 [JsonIgnore] 属性)时,Json returned 是:

[{}]

我这两种情况result是一样的,在转换为Json之前,用return Ok(result).

控制器

return 为给定 ClientId 提供信息的控制器方法:

[HttpGet]
[Route("{id}")]
public async Task<IActionResult> GetClientGroups(int id)
{
    var client = await db.Clients.FindAsync(id);
    if (client == null)
        return NotFound();

    // Works when using an anonymous type - the Json dictionary is not empty.
    var groups = db.Entry(client)
            .Collection(r => r.XClientGroups)
            .Query()
            .Include(r => r.ClientGroup)
            .Select(r => new { r.ClientGroup, r });

    // But fails when not using an anonymous type - the json dictionary is empty.
    //var groups = db.Entry(client)
    //        .Collection(r => r.XClientGroups)
    //        .Query()
    //        .Include(r => r.ClientGroup)
    //        .Select(r => new ClientGroupView(r.ClientGroup, r));
            
    var result = await groups.ToListAsync();
    if (result == null || result.Count <= 0)
        return NotFound();
    return Ok(result);
}

Client

public class Client
{
    public int ClientId { get; set; }
    public string ClientName { get; set; } = string.Empty;

    [JsonIgnore]
    public virtual ICollection<X_ClientGroup_Client> XClientGroups { get; set; }

    public Client()
    {
        XClientGroups = new HashSet<X_ClientGroup_Client>();
    }
}

ClientGroup

public class ClientGroup
{
    public int ClientGroupId { get; set; }
    public string GroupName { get; set; }

    [JsonIgnore]
    public virtual ICollection<X_ClientGroup_Client> XClients { get; set; }

    public ClientGroup()
    {
        XClients = new HashSet<X_ClientGroup_Client>();
    }
}

X_ClientGroup_Client

ClientClientGroup之间的多对多关系:

public class X_ClientGroup_Client
{
    public int RClientGroupClientId { get; set; }
    public int ClientGroupId { get; set; }
    public int ClientId { get; set; }

    [JsonIgnore]
    public ClientGroup ClientGroup { get; set; }
    [JsonIgnore]
    public Client Client { get; set; }
}

ClientGroupView

这里是对应匿名对象的ClientGroupView。它不包含任何 [JsonIgnore] 属性:

public class ClientGroupView
{
    public ClientGroup Group;
    public X_ClientGroup_Client Permissions;
    public ClientGroupView(ClientGroup group, X_ClientGroup_Client permissions)
    {
        this.Group = group;
        this.Permissions = permissions;
    }
}

如果我删除构造函数并像处理匿名对象那样构造对象,结果是一样的。

一个解决方案是更改 ClientGroupView 以包含字段而不是 类,但我更喜欢它包含 类 而不是 [=94= 的字段],因为更容易维护:

// I do not want to use this version of ClientGroupView
public class ClientGroupView
{
    public int RClientGroupClientId { get; set; }
    public int ClientId { get; set; }
    public int ClientGroupId { get; set; }
    public string GroupName { get; set; }

    public ClientGroupView(ClientGroup clientgroup, X_ClientGroup_Client permissions)
    {
        RClientGroupClientId = permissions.RClientGroupClientId;
        ClientId = permissions.ClientId;
        ClientGroupId = clientgroup.ClientGroupId;
        GroupName = clientgroup.GroupName;
    }
}

我不想使用这个版本的原因是因为它需要更多维护并且因为控制器在内部使用,即我不需要使用 DTO .

ClientGroupView.GroupClientGroupView.Permissions 是字段,不是属性。

添加{ get; set; }.