Hi,
Houston ? I've got a problem with my code to create a migration.
I have two "1..* relations"
-> Summary <-> Alineas
-> Paragraph <-> Alineas
In an attempt to create SOLID & DRY code, I used an 'IAlineaHolder' interface.
One more thing: since "Alineas" are all the same, I'd like to store theme in a single table, an use a single class.
So, I'd like to use a Table Per Hierarchy pattern to store 'Alineas' in the database (SQL Server), with the 'ParentType' (Enum value) as the discriminator.
This is my code sample :
Summary (parent part of the association)
public class Summary : IdentifierModelBase, IAlineaHolder, IParent, IDraftable, IIllustratable
{
//some properties
/// <summary>
/// Gets or sets the collection of alineas (sub-paragraphs) associated with the summary.
/// </summary>
[Display(Name = "Liste des alinéas")]
public virtual ICollection<Alinea> Alineas { get; set; }
}
Paragraph (parent part of the association)
public class Paragraph : IllustratedTopicSubdivisionBase, IAlineaHolder, IDraftable
{
/// <summary>
/// Gets or sets the collection of alineas (sub-paragraphs) associated with the paragraph.
/// </summary>
[Display(Name = "Liste des alinéas")]
public virtual ICollection<Alinea> Alineas { get; set; }
// some properties
}
Alinea (child part of the association)
public class Alinea : TopicSubdivisionBase
{
/// <summary>
/// Specifies the parent type of an alinea.
/// </summary>
public enum AlineaParentType
{
/// <summary>
/// The parent is a paragraph.
/// </summary>
[Display(Name = "Paragraphe")]
Paragraph,
/// <summary>
/// The parent is a summary.
/// </summary>
[Display(Name = "Résumé")]
Summary
}
/// <summary>
/// Gets or sets the content of the alinea.
/// </summary>
[Required(ErrorMessage = @"Le champ ""{0}"" est requis.")]
[Display(Name = "Contenu")]
public string Content { get; set; }
/// <summary>
/// Gets or sets the ID of the alinea that replaced this one.
/// </summary>
public Guid? ReplacedById { get; set; }
/// <summary>
/// Gets or sets the alinea that replaced this one.
/// </summary>
[ForeignKey(nameof(ReplacedById))]
public virtual Alinea? ReplacedBy { get; set; }
/// <summary>
/// Gets or sets the ID of the alinea that was replaced by this one.
/// </summary>
public Guid? ReplacesId { get; set; }
/// <summary>
/// Gets or sets the alinea that was replaced by this one.
/// </summary>
[ForeignKey(nameof(ReplacesId))]
public virtual Alinea? Replaces { get; set; }
/// <summary>
/// Gets or sets the parent of the alinea, which can be either a paragraph or a summary.
/// </summary>
[Display(Name = "Parent")]
[ForeignKey(nameof(ParentId))]
public virtual IAlineaHolder Parent { get; set; }
/// <summary>
/// Gets or sets the type of the parent of the alinea.
/// </summary>
[Display(Name = "Type de parent")]
public AlineaParentType ParentType { get; set; }
}
I tried to create the fluent API code for this, but when I ran the 'add-migration' command, it threw an error message. It seems that it can't create the relation because I used an interface for this property.
public virtual IAlineaHolder Parent { get; set; }
My goal is:
- To not change the inheritance of 'Summary' and 'Paragraph' classes,
- To use a single 'Alinea' class, given that the 'Alinea' for both 'Summary' and 'Paragraph' share the same properties,
- To store 'Alinea' instances in a single table with Parent Id as a foreign key to 'Summary' and another foreign key to 'Paragraph' by using a discriminator (TPH - Table Per Hierarchy) approach
- To ensure SOLID and DRY code principles are followed as much as possible.
If it's not possible to achieve this, I'll explore alternative approaches. I'd like to adhere to best practices to the greatest extent possible.
Can someone help me with this?
thank you in advance.
Please, thank you for being understanding if my English is not perfect. I am a French person trying to improve my English ;-p.