One to One HasRequired configuration not working

c# entity-framework entity-framework-6

Question

I have two sets of objects: Coupon and DiscountScheme.
Each have a connected object of {Type}Action, and identical configurations.
When making a request for Coupon, I do not get anything back, but the same query for DiscountScheme works as expected

A condensed version of the classes (The full code and sql for the tables can be found here):

public class CouponAction
{
    public int Id { get; set; }
    public virtual Coupon Coupon { get; set; }
}

public class Coupon
{
    public int Id { get; set; }
    public virtual CouponAction Action { get; set; }
}

public class DiscountSchemeAction
{
    public int Id { get; set; }
    public virtual DiscountScheme DiscountScheme { get; set; }
}

public class DiscountScheme
{
    public int Id { get; set; }
    public virtual DiscountSchemeAction Action { get; set; }
}

The configuration:

public class CouponActionMap : EntityTypeConfiguration<CouponAction>
{
    public CouponActionMap()
    {
        ToTable("CouponAction");
    }
}

public class CouponMap : EntityTypeConfiguration<Coupon>
{
    public CouponMap()
    {
        ToTable("Coupon");
        HasRequired(c => c.Action);
    }
}

public class DiscountSchemeActionMap : EntityTypeConfiguration<DiscountSchemeAction>
{
    public DiscountSchemeActionMap()
    {
        ToTable("DiscountSchemeAction");
    }
}

public class DiscountSchemeMap : EntityTypeConfiguration<DiscountScheme>
{
    public DiscountSchemeMap()
    {
        ToTable("DiscountScheme");

        HasRequired(ds => ds.Action);
    }
}

The query I am trying to make:

using(var context = new Context()/* My database context, using a custom wrapper framework*/)
{
  Console.WriteLine(context.Coupons.ToList()); // nothing
  Console.WriteLine(context.DiscountSchemes.ToList()); // the contents of the table
}

If I query the actions table, I do get the contents, but again for CouponAction I do not get the connected Coupon, and for DiscountScheme it works as expected.

1
1
3/5/2020 4:29:39 PM

Accepted Answer

The issue is with your 1-to-1 relationship. By default EF expects a 1-to-1 to be using the PKs on both tables. By putting a CouponID on your CouponAction you are not setting a 1-to-1 relationship, you are setting a 1-to-many/many-to-1. Nothing stops several CouponAction records from having the same CouponId. You could put a unique constraint on CouponID, but if that were the case then you may as well have the CouponAction's PK to be the CouponID. Hence, this is why I don't advise using "Id" as a PK name, but rather CouponId vs. DiscountId, etc.

If the relationship between coupon and action is truly 1-to-1 then get rid of the CouponId on the Action table, and ensure you're using the same ID value across both tables for the related records. You can test this by changing your mapping to configure EF to use CouponId on the CouponAction as it's PK. Once you do that, you should see your related records coming up.

Alternatively you can establish a many to 1 relationship (HasOne.WithMany()) from Action to Coupon, but no return reference without a CouponActionId on Coupon. Or you can set up a 1-to-many where Coupon contains an ICollection<CouponAction> CouponActions even though you intend to only have one action per coupon. But if it is 1-to-1 then I would highly recommend using the same PK value across both tables.

2
3/6/2020 12:31:22 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow