3

I am using ASP.NET Core 2.2 with EF Core 2.2 and SQL server.

I am currently working on a feature where I have the following classes:

TABLE Foo
-------------------------------------------------------------
Column                       Type          Remark
--------------------------------------------------------------
Id                           GUID          PK
IntroId                      GUID?         Nullable FK
IntroText                    Content       Navigation Property
--------------------------------------------------------------

TABLE Content
--------------------------------------------------------------
Column                       Type          Remark
--------------------------------------------------------------
Id                           GUID          PK
Text                         string
--------------------------------------------------------------

This is my fluent API configuration related to my issue:

Foo

builder.HasOne(b => b.IntroText)
    .WithOne()
    .IsRequired(false);

Content
Content only has configuration for itself.

Content can contain a lot of text and because of reasons, these things are not saved directly in the Foo table/class.

As you can see, I am trying to make sure that Content does not have a foreign key/navigation property to Foo. This is because these properties are not part of Content and because in the future more classes/tables can have stuff like IntroText's that are saved in the Content table and I dont want Content to be filled up with nullable foreign keys/navigation properties.

Is this possible with EF Core?

The error I get right now:

The child/dependent side could not be determined for the one-to-one relationship between 'Foo.IntroText' and 'Content'. To identify the child/dependent side of the relationship, configure the foreign key property. If these navigations should not be part of the same relationship configure them without specifying the inverse. See http://go.microsoft.com/fwlink/?LinkId=724062 for more details.


I would accept an answer that allows the database to have a relationship which I do not see in my codebase, but I would prefer that Content does not know anything about Foo

Thank you very much for your help!

S. ten Brinke
  • 2,557
  • 4
  • 25
  • 50
  • The error message contains the solution: *"configure the foreign key property"*. And the link shows how to do that. e.g. `.HasForeignKey(foo => foo.IntroId)`, – Ivan Stoev May 16 '19 at 14:55

2 Answers2

3

If you have an IntroTextId exposed in your Foo entity, then you need to associate it as the FK in the One-to-One relationship:

builder.HasOne(b => b.IntroText)
    .WithOne()
    .HasForeignKey(b => b.IntroTextId)
    .IsRequired(false);

Normally though I don't want FK properties exposed in my entities because this causes two sources of truth for what entity is referenced. (Foo.IntroTextId vs. Foo.IntroText.IntroTextId) In this case you leverage a shadow property for the FK:

builder.HasOne(b => b.IntroText)
    .WithOne()
    .HasForeignKey("IntroTextId")
    .IsRequired(false);

This is similar (and more intuitive) to using Map(MapKey) in EF 6 to map FKs without exposing properties.

.Map(x => x.MapKey("IntroTextId"));
Steve Py
  • 26,149
  • 3
  • 25
  • 43
0

Another possible solution is to handle the two keys as one. Since this is a one-to-one relationship, the keys of Tables Foo and Content should be the same value. You can achieve it in the following way with an attribute in the Foo class (since the FluentAPI was not specified as a requirement):

class Foo
{
   [Key, ForeignKey(nameof(Foo.IntroText))]
   public Guid Id { get; set; }

   public Content IntroText { get; set; }
}


class Content
{
   public Guid Id { get; set; }

   public string Text { get; set; }
}
Ryan Naccarato
  • 674
  • 8
  • 12