Zunino
Zunino

Reputation: 2034

Mapping owned type in separate table

I have a typical one-to-one relationship where one side owns the other. The owned side is a weak entity that does not have its own identifier in the database; instead, each record is identified by the owner's PK. Let me illustrate with an example where video records may have an associated transcription record.

video (id, description, storage_path)
transcription (video_id, text)

Video records have a life of their own. Some of them have a transcription available; most don't. My problem is figuring out how to model this properly with EF Core 3.1. For the video mapping I have something like:

public void Configure(EntityTypeBuilder<Video> builder)
{
    // ...
    builder.OwnsOne(video => video.Transcription).WithOwner();
}

How do I map the transcription side? When I tried creating a separate mapping for it, I got an error saying transcription cannot be mapped as non-owned.

Below are the relevant bits of the entity classes, and code-first ORM (using FluentMigrator).

Video

public class Video
{
    public int Id { get; set; }
    // ...
    public Transcription Transcription { get; set; }
}
public class VideoTable : Migration
{
    public override void Up()
    {
        Create.Table("videos")
            .WithColumn("id").AsInt64().PrimaryKey().Identity()
            // ...
    }
}
public class VideoMap : IEntityTypeConfiguration<Video>
{
    public void Configure(EntityTypeBuilder<Video> builder)
    {
        builder.ToTable("videos");
        builder.Property(v => v.Id).HasColumnName("id").IsRequired();
        // ...
        builder.OwnsOne(v => v.Transcription, tbuilder => {
            tbuilder.WithOwner().HasForeingKey("VideoId");
            tbuilder.Property("VideoId").HasColumnName("video_id");
            // ...
            tbuilder.ToTable("transcriptions");
        });
    }
}

Transcription

public class Transcription
{
    public int VideoId { get; set; }
    // ...
}
public class TranscriptionTable : Migration
{
    public override void Up()
    {
        Create.Table("transcriptions")
            .WithColumn("video_id").AsInt64().PrimaryKey()
            // ...

        Create.ForeignKey("fk_video_transcription")
            .FromTable("transcriptions").ForeignColumn("video_id")
            .ToTable("videos").PrimaryColumn("id");
    }
}

What am I missing?

Note: I'm aware a relationship like this could be implemented with the owned entities' fields incorporated into the owning table. However, there are practical reasons why they should be kept separate.

Upvotes: 1

Views: 2461

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205849

Owned types are always (can obnly be) configured through their owner entity, and more specifically, through their own builder returned by the OwnsOne method or provided as an argument of the Action<T> argument of the OwnsOne method of the owner entity builder.

Note that you already are using the owned entity builder to call .WithOwner() which in turn is used to configure the relationship between the owner and owned. For owned only related configuration like properties, column names, table etc. you use directly the corresponding owned builder fluent methods.

e.g.

builder.OwnsOne(video => video.Transcription, ownedBuilder =>
{
    ownedBuilder.WithOwner()
        .HasForeignKey("VideoId");

    ownedBuilder.Property("VideoId")
        .HasColumnName("video_id");

    ownedBuilder.ToTable("Transcription");
});

Upvotes: 2

Related Questions