41686d6564
41686d6564

Reputation: 19641

Multiple optional one-to-one relations where one (any) of them is required

I checked this one and other related questions, but couldn't find a working solution for my case.

So, I have 3 entities, PrintingMethod, PrintingSubMethod, and PrintPricing. The rules are:

Here's the first two entities:

Public Class PrintingMethod
    Public Property Id As Integer
    Public Property Name As String
    Public Property SupportsAdditionalColors As Boolean

    Public Overridable Property SubMethods As ICollection(Of PrintingSubMethod)
    Public Overridable Property AdditionalColorPricing As PrintPricing
End Class


Public Class PrintingSubMethod
    Public Property Id As Integer
    Public Property Name As String

    Public Property PrintingMethodId As Integer

    <ForeignKey("PrintingMethodId")>
    Public Overridable Property ParentMethod As PrintingMethod

    Public Overridable Property Pricing As PrintPricing
End Class

And here's an illustration of the third one:

Public Class PrintPricing
    Public Property Id As Integer

    <ForeignKey("LinkedSubMethod")>
    Public Property SubMethodId As Integer

    <ForeignKey("LinkedMethod")>
    Public Property MethodId As Integer

    Public Overridable Property LinkedSubMethod As PrintingMethodCode
    Public Overridable Property LinkedMethod As PrintingMethod
End Class

So, is this possible to achieve using DataAnnotations or Fluent API? If not please feel free to suggest alternatives.

Notes:

Upvotes: 0

Views: 173

Answers (1)

galdin
galdin

Reputation: 14034

Your relationship graph would look something like this, if I read your question right:

PrintingMethod       [1:n]  PrintingSubMethod
PrintingMethod    [0..1:1]  PrintPricing   
PrintingSubMethod [0..1:1]  PrintPricing

It's worth noting that a pure one to one relationship is not possible because the principal entity must always appear first (without the dependent entity existing which defeats the 1:1 constraint we're after). So a 1:1 in practice tends to be a one-to-zero-or-one-relationship.

Each PrintingSubMethod must have one PrintPricing

So enforcing this rule would require you to handle it at some other layer.


public class PrintPricing 
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    // You may want to uncomment the "navigation" properties, 
    // but I'm going to leave it commented so you know this is
    // not required for it to establish the relationship correctly, 
    // because this class represents the principal end of the relationship
    // public virtual PrintingMethod Method { get; set; }
    // public virtual PrintingSubMethod SubMethod { get; set; }
}

public class PrintingMethod 
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [ForeignKey("Pricing")] // foreign keys go on the dependent ends for 0:1 relationships
    public int Id { get; set; }
    public virtual List<PrintingSubMethod> SubMethods { get; set; }

    public virtual PrintPricing Pricing { get; set; }
}

public class PrintingSubMethod
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [ForeignKey("Pricing")]
    public int Id { get; set; }
    public virtual PrintingMethod Method { get; set; }

    public virtual PrintPricing Pricing { get; set; }
}

You may also manually define foreign keys for the PrintingMethod [1:n] PrintingSubMethod relationship if you'd like, but EF is smart enough to figure that by itself, so that's optional. I personally prefer defining foreign keys manually.

Upvotes: 1

Related Questions