0

I'm trying to setup a one to zero-or-one relationship, I thought I had it worked out, but I was wrong as I testing further. I clearly do not understand FluentAPI too well, but I also see that many have had the same or similar issue I am experiencing

Here are my Classes:

public class BaseLogObject
{
    public BaseLogObject()
    {
        Oid = Guid.NewGuid();
        Date = DateTime.Now;
    }

    [Key]
    [Column(Order = 0)]
    public Guid Oid { get; set; }

    [ScaffoldColumn(true)]
    [Display(Name = "Date")]
    [Required]
    [Column(Order = 1)]
    public DateTime Date { get; set; }
}

public class AccessLog : BaseLogObject
{
    public virtual ErrorLog ErrorLog { get; set; }
}

public class ErrorLog : BaseLogObject
{
    //Hoping to keep this property, but .MapKey give "Unique" error
    [Display(Name = "Access Log")]
    public virtual Guid? AccessLogID { get; set; }

    public virtual AccessLog AccessLog { get; set; }
}

FluentAPI setup:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<ErrorLog>()
        .HasOptional(a => a.AccessLog)
        .WithOptionalDependent(x => x.ErrorLog)
        .Map(a => a.MapKey("AccessLogID"));

    //Thought this worked, but AccessLogID became the PrimaryKey
    //modelBuilder.Entity<ErrorLog>().HasKey(x => x.AccessLogID);
    //modelBuilder.Entity<ErrorLog>().HasRequired(x => x.AccessLog);

    //This creates a new column in SQL (AccessLog_Oid)
    //modelBuilder.Entity<AccessLog>()
    //  .HasOptional(pi => pi.ErrorLog)
    //  .WithOptionalDependent(x => x.AccessLog);

    //Tried reversing the relationship, no go
    //modelBuilder.Entity<AccessLog>()
    //  .HasOptional(x => x.ErrorLog)
    //  .WithRequired(x => x.AccessLog);

    base.OnModelCreating(modelBuilder);
}   

AccessLogID: Name: Each property name in a type must be unique. Property name 'AccessLogID' is already defined.

I understand that AccessLogID is a duplicate, but was hoping that I could leave it in my ErrorLog model so I can reference it throughout the application (techincally, I am saving the Guid in a Session and logging Errors/Exceptions to it as needed, I am trying to avoid storing the entire Object, just the Guid).

Derek
  • 653
  • 7
  • 20

1 Answers1

1

Asked many times out here. It is not a well supported relationship. You either have to share a primary key, or set it up as follows:

modelBuilder.Entity<ErrorLog>()
    .HasOptional(e => e.AccessLog)
    .WithMany()
    .HasForeignKey(e => e.AccessLogID);

Similar here and here.

Steve Greene
  • 12,029
  • 1
  • 33
  • 54
  • I've set this up, it the intention to change `public virtual ErrorLog ErrorLog { get; set; }` to `public virtual List ErrorLogs { get; set; }`? (on the `AccessLog` class) – Derek Mar 08 '18 at 13:38
  • No, you don't need to do that. The `WithMany()` is just a mechanism(hack) for EF to configure a working solution. – Steve Greene Mar 08 '18 at 15:24
  • I just noticed that the `AccessLog` table has `ErrorLog_Oid` in it when I have `public virtual ErrorLog ErrorLog { get; set; }`. Is there something I need to configure with `.Entity` or does AccessLog need to have a ForeignKey for the ErrorLog property? – Derek Mar 08 '18 at 17:59
  • Correct. Your other option is to make AccessLogId both a PK and a FK to ErrorLog. Your inheritance structure would interfere with that currently. – Steve Greene Mar 08 '18 at 19:29
  • I always thought the inheritance of `BaseLogObject` would get in the way of something, am I able to `override` the Oid and put Annotations on it? Thank you for all your help btw. – Derek Mar 08 '18 at 20:38
  • I'm not sure. The only inheritance I've used is TPH. – Steve Greene Mar 08 '18 at 20:56