Reputation: 571
I'm trying to develop a data model for c# .net Core application using Entity Framework Code first.
What I basicaly have is a data model bellow.
There are tables Dog
and Person
. They each contain different information. For example I can have different type of dogs. Person can have something specific and that would be not applicable for dogs.
There is 1:1 relation between Person
and Item
. The same relation is between Dog
and Item
.
In addition to that table ItemReference
contains child-parent relations between Items. For example there is child - parent relation between dog and person (dog owner - dog or persons may be siblings)
I need to make alphabetical list of dogs and persons (mix them up).In addition I need to be able to get to Details page for each of the following.
Using this feels really stupid as there might be more tables in the future. For Example Cat
or Car
and I would need to rework these If statements each time.
@foreach (var x in Model.Item.OrderBy(y=>y.ItemName))
{
if (x.ItenType == "Dog")
{
<li><a asp-page="DogDetails" asp-route-id="@x.Item.Dog.Id">@x.ItemName</a></li>
}
if (x.ItenType == "Person")
{
<li><a asp-page="PersonDetails" asp-route-id="@x.Item.Person.Id">@x.ItemName</a></li>
}
}
Anyone knows how to make such a data model so it is more intelligent design?
Any help greatly appreciated
Tables Dog
, Person
and Item
will look like this:
Dog
Id DogName DogTypeId DogStatusId ItemId
1 "Alex" 1 1 1
2 "Rex" 2 1 2
Person
Id PersonName PersonStatusId ItemId
1 "Joe" 1 3
2 "Jane" 2 4
Item
Id ObjectName ItemType
1 "Alex" "Dog"
2 "Rex" "Dog"
3 "Joe" "Person"
4 "Jane" "Person"
Upvotes: 0
Views: 81
Reputation: 239440
Your object graph isn't entirely clear. It looks like Dog
and Person
are just related to Item
, but based on your description and brief code sample, it would appear that they're actually types of items. If that's the case, you should be employing an inheritance strategy, not composition.
public class Item
public class Dog : Item
public class Person : Item
By default, EF will handle inheritance with a TPH (table per hierarchy) strategy, which doesn't seem appropriate here. Instead, I think you're going to want TPT (table per type) which can be achieved by using the Table
attribute on your derived classess:
[Table("Dogs")]
public class Dog : Item
[Table("Persons")]
public class Person :
What this will do is create three tables, Dogs
, Persons
, and Items
. Any data common to all items, regardless of whether it's a dog or person, will obviously go on your Item
class and will end up in the Items
table. Foreign keys will be added on both the Dogs
and Persons
table pointing to the Items
table. When you retrieve a Dog
, for example, EF will automatically join the corresponding record in Items
to create a complete Dog
.
This then gives you some special abilities with your queries. You can generically get all items, regardless of type, with _context.Items
of course, but you can also potentially have separate DbSet
s for Dog
and Person
, allowing you to query those independently: e.g. _context.Dogs
. Even without an explicit DbSet
, you can utilize the generic Set<TEntity>
method: _context.Set<Dog>()
. Additionally, you can use OfType<TEntity>
to filter the Items
set: _context.Items.OfType<Dog>()
.
Lastly, even if you just retrieve Items
, EF still tracks what ultimate type each Item
is, which means you can do things like pattern matching:
if (item is Dog dog)
{
// `dog` is now a variable in this scope of your `item` downcast to `Dog`
}
Or in switch statements:
switch (item)
{
case Dog dog:
// do something with `dog`
break;
case Person person:
// do something `person`
break;
default:
// do something with generic items (`item`)
break;
}
EDIT
I realized that I only alluded to the following, rather than stating explicitly. Since Dog
and Person
are totally different tables in TPT, you can define totally separate relationships there. For example, Dog
could have a relationship with DogStatus
, without affecting anything that's going on with Person
. You can technically still do this even with TPH, but you'd end up with a bunch of nullable foreign keys on the Items
table and that would just be a mess and also breaks normalization.
Upvotes: 2