The whole solution of inheritance relation mapping in ORM--single table inheritance system, one entity one concrete table, one Entity one extension table, interface mapping
This article covers the following topics:
1. Single-Table inheritance system
2. One entity, one specific table
3. One Entity one extension table
4. Interface implementation mapping VS base class inheritance mapping
1. Single-Table inheritance system
The so-called one-table inheritance system is to use a database table to store all the entities in the inheritance system data. Single-table inheritance system for that kind of inheritance system, the number of entities is relatively small, the total number of records is relatively small, the subclass of the parent class of the property extension is also relatively small situation.
The advantage of a single table inheritance system is to read/write data for each entity in the inheritance system, all you need to do is operate a table, perform better, and, if you add a new inheritance class, or extend the entity attributes, you can only increase or decrease the field of a table, which is easy to maintain; The main disadvantage is that because all entities share a single table, The table will have more data for null field values, waste some storage space, and, if the number of records is too high, the table will be larger and also affect the reading and writing performance of the table.
Simple single Table Inheritance system
Let's take a look at a hypothetical example first:
[Table("AllInOneTable")]
public interface Parent : IEntity
{
[PrimaryKey]
int ID { get; }
string Name { get; set; }
}
[Table("AllInOneTable")]
public interface AnotherParent : IEntity
{
[PrimaryKey]
int ID { get; }
int Age { get; set; }
}
[Table("AllInOneTable")]
public interface Child : Parent, AnotherParent
{
[PrimaryKey]
new int ID { get; set; }
DateTime Birthday { get; set; }
}
We can see, in the example above, that we have defined two base entity parent and anotherparent,child entities to inherit from two base classes at the same time. Note that the lines in the code are bold, and if multiple different base interfaces contain properties of the same name, the code fails to compile, and you need to use the new keyword like this to avoid compilation failures.
Here, we're using a single table inheritance system, and note that each entity maps to the Allinonetable table, except that for each entity, only some of the fields of the Allinonetable table are used.
However, when you define a single table inheritance in such a simple way, because you can't know exactly which subclass a row of data is actually corresponding to when you read data from a table, in practice, we usually attach some query conditions and field defaults.
A single table inheritance system with attached conditions
When using a single table inheritance system scheme, the different subclasses in the inheritance system extend not only the attributes of the parent class, but also some field query conditions and default values. The NBear.Common.TableAttribute Additionalwhere and Additionalinsert properties are used here, and for detailed usage of these two properties, refer to the table mappings.
Take a look at the following code:
public interface Message : IEntity
{
[PrimaryKey]
int ID { get; }
string Title { get; set; }
string Content { get; set; }
DateTime UpdateTime { get; set; }
}
[Table("Message", AdditionalInsert = "[MessageType] = 1", AdditionalWhere = "[MessageType] = 1")]
public interface CommonMessage : Message
{
int UserID { get; set; }
}
[Table("Message", AdditionalInsert = "[MessageType] = 2", AdditionalWhere = "[MessageType] = 2")]
public interface SpecialMessage : Message
{
int GroupID { get; set; }
}
What we actually want to persist here is two entities commonmessage and Specialmessage, they have a common abstract parent class message, and the parent class is not used directly as an abstract class. We keep the entire inheritance system in the message datasheet. Contains all the properties of Commonmessage and Specialmessage. But, as we said in the hypothetical example above, if you query the message table directly and return the corresponding field data for Commonmessage, then the data that is inserted into the specialmessage is returned, and vice versa, which is clearly not the case.
Therefore, we need to define additional query conditions and insert default values, that is, add a messagetype field for the Message table, the field value of 1 represents commonmessage, and a value of 2 means that the row data is specialmessage. When Additionalwhere and Additionalinsert are defined in the above code, the query commonmessage or Specialmessae only returns records that actually correspond to their messagetype value, when the data is inserted , the framework also automatically sets the necessary MessageType defaults for Commonmessage and Specialmessage.