-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Configuring non-ownership navigation to the owner throws #13912
Comments
@smitpatel to respond |
They are not ignored. Since |
|
@ZombieProtectionAgency - When you put
Due to foreign key constraint, CreatorId will take exactly same value as Id on referenced data. If you are storing that in single row in same table, it is exactly same data. If you still have doubts, please describe in detail, what is expected database schema you are looking for and why above configuration is incorrect for that. |
I was expecting to be able to see something like this in the database Entities My goal is to end up with the migration builder snippet and its resulting SQL from the original post while using an Owned property. This, specifically CREATE TABLE [Entities] (
[Id] uniqueidentifier NOT NULL,
[CreatorId] uniqueidentifier NOT NULL,
CONSTRAINT [PK_Entities] PRIMARY KEY ([Id]),
CONSTRAINT [FK_Entities_Entities_CreatorId] FOREIGN KEY ([CreatorId]) REFERENCES [Entities] ([Id])
); |
If that is the stored data, then the relationship is one to many & not one-to-one as you are configuring with 2 reference navigations. |
So I am misunderstanding OwnedAttribute functionality? Is it possible to do what I want? |
It is possible with owned collection which is feature in 2.2 release |
Could you give me an example of how that solves my issue please? Since each parent "Entity" only references one other entity I didnt think I needed a collection. I dont need to know which records were created by any particular entity. |
Each parent "Entity" is referencing multiple "ExtraData" entities. Else why 4 different ExtraData.CreatorId which is foreign key has same value pointing to same parent with Entity.Id = 1. |
I am still not convinced this is not an issue. As I said in the original post, the following code works EXACTLY as I expect. It creates a perfect migration, a perfect schema, and all navigations work as expected. I dont see how being self-referential should change that behavior. public class SomeType
{
public Guid Id { get; set; }
public ExtraData ExtraData { get; set; }
} Which generates this Up migration migrationBuilder.CreateTable(
name: "SomeTypes",
columns: table => new
{
Id = table.Column<Guid>(nullable: false),
ExtraData_CreatorId = table.Column<Guid>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SomeTypes", x => x.Id);
table.ForeignKey(
name: "FK_SomeTypes_Entities_ExtraData_CreatorId",
column: x => x.ExtraData_CreatorId,
principalTable: "Entities",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}); Which generates this SQL script CREATE TABLE [SomeTypes] (
[Id] uniqueidentifier NOT NULL,
[ExtraData_CreatorId] uniqueidentifier NOT NULL,
CONSTRAINT [PK_SomeTypes] PRIMARY KEY ([Id]),
CONSTRAINT [FK_SomeTypes_Entities_ExtraData_CreatorId] FOREIGN KEY ([ExtraData_CreatorId]) REFERENCES [Entities] ([Id]) ON DELETE CASCADE
); |
Even in this case, |
@ZombieProtectionAgency I believe the key is in this part of Smit's initial explanation:
TL;DR: In this case the prediction of EF Core is incorrect, and you were trying to configure a model with two separate relationships. Details:EF Core is trying to infer what your intent is when you have: public class Entity
{
public Guid Id { get; set; }
public ExtraData ExtraData { get; set; }
}
[Owned]
public class ExtraData
{
public Guid CreatorId { get; set; }
public Entity Creator { get; set; }
} Entity.Extradata and ExtraData.Creator in your model matches an EF Core convention that basically says "if there are two objects with matching navigation properties pointing to each other, create a single relationship for them, and then configure the navigation properties to be the reverses of each other". It just happens that in your particular model this is not the intent, and the navigation properties are supposed to represent 2 separate relationships: You are using one ExtraData to group information about the creator of an entity (so, in terms of the EF Core model, there is a one-to-one relationship between Entity and its ExtraData), but then each entity (with its ExtraData) will have a Creator, that happens to be different Entity, and each of the Entities can be the Creator for multiple other entities (hence there is a separate one-to-many relationship). EF Core conventions are simple rules that try to guess what your intent is, but are not expected to always get it right. I personally find it a bit puzzling how our guess as humans can be sometimes so much better, but that is because we are usually applying additional domain information to make our decisions. E.g. you know very well what the word "Creator" means, so you understand immediately that if an Entity has a Creator, that Creator is a different Entity. But EF Core is asked to make same guess in a reproducible way, and with zero knowledge of the meaning of the "Creator" string. Now, the best way I can think of to make this model work the way you want, is to explicitly configure the relationship. I have attempted to do this in the following snippet: using System;
using Microsoft.EntityFrameworkCore;
namespace World
{
internal class Program
{
private static void Main(string[] args)
{
using (var db = new MyContext())
{
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
}
}
}
public class Entity
{
public Guid Id { get; set; }
public ExtraData ExtraData { get; set; }
}
[Owned]
public class ExtraData
{
public Guid CreatorId { get; set; }
public Entity Creator { get; set; }
}
public class MyContext: DbContext
{
public DbSet<Entity> Entities { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
@"server=(localdb)\mssqllocaldb;database=hey;integrated security=true;connectretrycount=0");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Entity>()
.OwnsOne(e => e.ExtraData)
.HasOne(ed => ed.Creator)
.WithMany()
.HasForeignKey(ed => ed.CreatorId);
}
}
} Now, unfortunately, it seems that we currently don't support this. I get the exception below from this configuration code. I will let @smitpatel comment if there is a workaround that works.
|
I had actually tried that and ran into the same issue. I am not as familiar with the Fluent API so I assumed I was doing something wrong. Since this does appear to be an issue, just not the original one I thought it was, I think the title should change? It might be better for somebody more familiar with what is happening to reword it though. I would probably end up making it nonsensical. |
First off I am terrible at wording and I am not 100% sure how to describe this issue. I searched around a bit but I couldn't find an existing issue that fully captured this so I decided to make a new one.
To summarise: When using an
OwnedAttribute
property with a one-to-many FK on the type that the FK references the FK and Column are being ignored but it works as expected for every other type and it works as expected if I cut + paste the columns from theOwnedAttribute
type directly onto the original type.I am trying to use
OwnedAttribute
in a Code First project to add some common columns to many tables.This works as expected when added to a type,
which results in a migration of
My issue is that when I add this property to the type that it references,
The FK and its column are completely ignored
If, instead, I add these columns directly to
Entity
everything works as expected.Also vaguely related, I commented on another issue with this but trying to rename the FK column on the
OwnedAttribute
type to strip the prefix (ExtraData_
) I receive the following error (even if I explicitly set the PKey and FKey.)Further technical details
EF Core version: 2.1.4.0
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10 Enterprise
IDE: Visual Studio Professional 2017 15.7.6
The text was updated successfully, but these errors were encountered: