'Relationship with [NotMapped] and [Keyless] ends up with NULL object in aspnet core

Using aspnet core webapi, there is a class without an Id called CustomRegistryKey that is used as an ICollection<T> in another class called WindowsBase. When I was compiling I learned about the [Keyless] decorator that was required as I didn't include the public int Id {get;set} line when creating the class.

The hope was that I would be able to generate an object, and insert it directly into the table and retrieve later when using GET request on the API controller.

When a PUT command is issued, and the object is converted to JSON and the payload is received, the API always returns NULL on the CustomRegistryKey ICollection in the returned data.

The classes below are simplified versions of the actual classes for brevity. Having tried removed the [Keyless] and the [NotMapped] decorators from each class threw errors either at compile or when trying to GET/PUT on the api controller.

How do I go about creating an object, that is not referencing another table, to create an object that does not need to be indexed, but can be retrieved using GET calls so the data in the Collection can be iterated through and read like a dictionary/array?

CustomRegistryKey.cs
[Keyless]
public class CustomRegistryKey
{
    public string Hive { get; set; }
    public string Key { get; set; }
    public string ValueType { get; set; }
}
WindowsBase.cs
public class WindowsBase
{
    public int Id { get; set; }
    public string Status { get; set; }
    public string Release { get; set; }
    
    [NotMapped]
    public ICollection<CustomRegistryKey> CustomRegistryKeys { get; set; }
}

When I tried to remove [NotMapped] the API will compile, but a GET will return this kind of error message:

System.InvalidOperationException: Unable to determine the relationship represented by navigation 'WindowsBase.CustomRegistryKeys' of type 'ICollection<CustomRegistryKey>'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

Using Invoke-RestMethod and creating an object to publish to the API works fine:

$CSR1 = @{
  Hive = "HKLM"
  Key = "SOFTWARE\Microsoft\Windows"
  ValueType = "REG_SZ"
}
$CSR2 = @{
  Hive = "HKLM"
  Key = "SOFTWARE\Microsoft\Adobe"
  ValueType = "REG_SZ"
}
$Body = @{
  Id = 0
  Status = "Working"
  Release = "2022"
  CustomRegistryKeys = @($CSR1,$CSR2)
} | ConvertTo-Json
Invoke-RestMethod -Uri http://localhost/api/WindowsBase -Method Put -Body $Body

The output from the GET request will look like this everytime, even with a successful PUT request:

[
    {
      "id": 1,
      "status": "Working",
      "release": "2022",
      "customregistrykeys": null
    }
]

The reason I haven't included an Id on the CustomRegistryKey class comes from there is not table/controller setup for this to be referenced. I just wanted the object stored in the table so I can call it when it's required.

If I add the Id, does not the object need to exist under its own Controller first and be referenced? Is there something I have overlooked or a missing?



Solution 1:[1]

This relation is many to one, then it should be
Change to this

[Keyless]
public class CustomRegistryKey
{
    public string Hive { get; set; }
    public string Key { get; set; }
    public string ValueType { get; set; }
    public virtual WindowsBase WindowsBase { get; set;}
}

Change to this

public class WindowsBase
{
    public int Id { get; set; }
    public string Status { get; set; }
    public string Release { get; set; }
    
    public virtual ICollection<CustomRegistryKey> CustomRegistryKeys { get; set; }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 sambath999