-
Notifications
You must be signed in to change notification settings - Fork 63
Description
Hey.
for my understanding the union type and the entity type hierarchy mapping from EF seems like a perfect match for each other.
But due to the limitation of needing an empty abstract class or interface to declare a union type or probably some bugs happening, it seems like this combination of features does not work currently.
Let's look at the following entity structure (simplified):
public abstract class BaseItem {
public int Id { get; set; }
public string Name { get; set; }
public double Weight { get; set; }
}
public class General : BaseItem {
public string Note { get; set; }
}
public class Container : BaseItem {
public double WeightLimit { get; set; }
}
public class Weapon : BaseItem {
public int Damage { get; set; }
}
public class Armor : BaseItem {
public string Class { get; set; }
}And the corresponding DbContext:
public class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : DbContext(options)
{
public DbSet<BaseItem> Items => Set<BaseItem>();
public DbSet<General> GeneralItems => Set<General>();
public DbSet<Container> Containers => Set<Container>();
public DbSet<Weapon> Weapons => Set<Weapon>();
public DbSet<Armor> Armors => Set<Armor>();
}Following the needed definitions for the schema (for this example we disregard the limitation of an empty abstract class needed for defining a union):
schema.AddUnion<BaseItem>("ItemUnion", "Get items");
schema.Type<BaseItem>().AddAllPossibleTypes();We should be able to perform the following query:
query {
items {
... on General {
id
name
weight
note
__typename
}
... on Container {
id
name
weight
weightLimit
__typename
}
... on Weapon {
id
name
weight
damage
__typename
}
... on Armor {
id
name
weight
class
__typename
}
}
}And receive the following example json as return:
{
"data": {
"items": [
{
"id": 1,
"name": "Fork",
"weight": 1,
"type": "General",
"note": "Normally used to eat",
"__typename": "General"
},
{
"id": 2,
"name": "Chest",
"weight": 5,
"type": "Container",
"weightLimit": 25,
"__typename": "Container"
},
{
"id": 3,
"name": "Iron Sword",
"weight": 1,
"type": "Weapon",
"damage": 3,
"__typename": "Weapon"
},
{
"id": 4,
"name": "Iron Chestplate",
"weight": 1,
"type": "Armor",
"class": "Heavy",
"__typename": "Armor"
}
]
}
}If the limitation of an empty abstract class for a union type could be disregarded, this would seem like a good use.
But due to the limitation we cannot do it. To get a working solution for EF and the union type, we can declare a new interface called IItem and let it be inherited by the entities. So the new class heads would look like that:
public interface IItem { }
public class General : BaseItem, IItem
public class Container : BaseItem IItem
public class Weapon : BaseItem, IItem
public class Armor : BaseItem, IItemThe updated schema definition would then look like this:
schema.AddUnion<IItem>("ItemUnion", "Get items");
schema.Type<IItem>().AddAllPossibleTypes();A working entity for EF needs at least a key property, e.g. Id. So we can not use AItem to reference it as a DbSet or in a relation. An interface is disqualified for EF due to the same reason.
The items query has obviously BaseItem as type as the schema generation does not now the intended usage. Changing the return type by utilizing the Returns method does change the typing in the schema as needed. But obviously the data resolving is now not correct. Although we can overwrite the resolving by utilizing the Resolve method, I did not find a way to utilize it so return data is correct.