Skip to content
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

Throw better error message for owned entity without owner can be attached to context #21954

Closed
mnver1 opened this issue Aug 6, 2020 · 6 comments · Fixed by #26398
Closed
Labels
area-change-tracking closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-enhancement
Milestone

Comments

@mnver1
Copy link

mnver1 commented Aug 6, 2020

I don't know if this is by-design or not, but it doesn't make sense to me so I thought I report it.

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

        public Owned Owned { get; set; }
    }

    [Owned]
    class Owned
    {
        public int Foo { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Test_InMemoryDb();

            Test_Postgres();
        }

        static void Test_InMemoryDb()
        {
            var optionsBuilder = new DbContextOptionsBuilder();

            optionsBuilder.UseInMemoryDatabase("Test_OwnedEntityWithoutOwner");

            var context = new Context(optionsBuilder.Options);

            context.Database.EnsureDeleted();

            context.Database.EnsureCreated();

            var owned = new Owned();

            context.Add(owned);                                     // expected: exception

            var entry = context.Entry(owned);

            Assert.True(entry.State == EntityState.Added);

            var writtenEntitiesCount = context.SaveChanges();       // expected: exception

            Assert.True(writtenEntitiesCount == 1);                 // excepted: 0

            Assert.True(entry.State == EntityState.Unchanged);

            owned.Foo = 1;

            context.ChangeTracker.DetectChanges();

            Assert.True(entry.State == EntityState.Modified);   

            writtenEntitiesCount = context.SaveChanges();           // expected: exception

            Assert.True(writtenEntitiesCount == 1);                 // excepted: 0
        }

        static void Test_Postgres()
        {
            var optionsBuilder = new DbContextOptionsBuilder();

            optionsBuilder.UseNpgsql("Server = 127.0.0.1; Port = 5432; Database = Test_OwnedEntityWithoutOwner; User Id = postgres; Password = 123;");

            var context = new Context(optionsBuilder.Options);

            context.Database.EnsureDeleted();

            context.Database.EnsureCreated();

            var owned = new Owned();

            context.Add(owned);                                     // expected: exception

            var entry = context.Entry(owned);

            Assert.True(entry.State == EntityState.Added);

            var writtenEntitiesCount = context.SaveChanges();       // expected: exception

            Assert.True(writtenEntitiesCount == 0);

            Assert.True(entry.State == EntityState.Unchanged);

            owned.Foo = 1;

            context.ChangeTracker.DetectChanges();

            Assert.True(entry.State == EntityState.Modified);

            Assert.Throws<DbUpdateConcurrencyException>(() => context.SaveChanges());             // expected: a meaningful exception
                                                                                                  // Exception message: 'Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. 
        }

    }

Test.zip

Further technical details

EF Core version: 3.1.6
Database provider: Several
Target framework: .NET Core 3.0

@ajcvickers
Copy link
Contributor

Note for triage: Repros on 3.1.6, throws when calling SaveChanges in latest daily:

/usr/share/dotnet/dotnet /home/ajcvickers/Repros/Test/Test/bin/Debug/netcoreapp3.0/Test.dll
Unhandled exception. System.InvalidOperationException: The value of 'Owned.OwnerId' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known.
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.PrepareToSave()
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.GetEntriesToSave(Boolean cascadeChanges)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(DbContext _, Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.Storage.NonRetryingExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()
   at Test.Program.Test_InMemoryDb() in /home/ajcvickers/Repros/Test/Test/Program.cs:line 49
   at Test.Program.Main(String[] args) in /home/ajcvickers/Repros/Test/Test/Program.cs:line 24

@ajcvickers
Copy link
Contributor

Note from triage: this was a bug in 3.1, however putting this on the backlog to throw a better exception message for this case.

@EmpeRoar
Copy link

any progress on this issue?

@smitpatel smitpatel changed the title Owned entity without owner can be attached to context Throw better error message for owned entity without owner can be attached to context Nov 24, 2020
@ajcvickers
Copy link
Contributor

@EmpeRoar No, but the issue here is only tracking throwing with a more helpful exception message. An owned entity without an owner cannot be tracked.

@EmpeRoar
Copy link

we redesign our database relationships since we are using database-first. and it fixed it,

@ethembynkr
Copy link

ethembynkr commented Dec 15, 2020

I get same error when updating the entity with primary key 0(zero). How can I fix it?

public class User
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Id { get; set; }
        public LocalizedEntity NationalityName { get; set; }
    }
[Owned]
public class LocalizedEntity
    {
        public string Primary { get; set; }
        public string Secondary { get; set; }
    }

Error:

InvalidOperationException: The value of 'User.NationalityName#LocalizedEntity.UserId' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known.

EF Core version: 5.0.0

@ajcvickers ajcvickers self-assigned this Oct 18, 2021
ajcvickers added a commit that referenced this issue Oct 18, 2021
Fixes #19383
Fixes #17123

> No suitable constructor was found for entity type 'BlogNone'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'did' in 'BlogNone(string title, int did)'; cannot bind 'notTitle' in 'BlogNone(string notTitle, Guid? shadow, int id)'; cannot bind 'dummy' in 'BlogNone(string title, Guid? shadow, bool dummy, int id)'; cannot bind 'dummy', 'description' in 'BlogNone(string title, Guid? shadow, bool dummy, int id, string description)'. Note that only mapped properties can be bound to constructor parameters. Navigations to related entities, including references to owned types, cannot be bound.

Fixes #26341

> The 'DateOnly' property 'Blog.PostedOn' could not be mapped because the database provider does not support this type. Consider converting the property value to a type supported by the database using a value converter. See https://aka.ms/efcore-docs-value-converters for more information. Alternately, exclude the property from the model using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

Or if the store type is specified:

> The 'DateOnly' property 'Blog.PostedOn' could not be mapped to the database type 'datetime2' because the database provider does not support mapping 'DateOnly' properties to 'datetime2' columns. Consider mapping to a different database type or converting the property value to a type supported by the database using a value converter. See https://aka.ms/efcore-docs-value-converters for more information. Alternately, exclude the property from the model using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

Fixes #21954

> Cannot save instance of 'Skinner' because it is an owned entity without any reference to its owner. Owned entities can only be saved as part of an aggregate also including the owner entity.
@ajcvickers ajcvickers modified the milestones: Backlog, 7.0.0 Oct 18, 2021
@ajcvickers ajcvickers added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Oct 18, 2021
ajcvickers added a commit that referenced this issue Oct 19, 2021
Fixes #19383
Fixes #17123

> No suitable constructor was found for entity type 'BlogNone'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'did' in 'BlogNone(string title, int did)'; cannot bind 'notTitle' in 'BlogNone(string notTitle, Guid? shadow, int id)'; cannot bind 'dummy' in 'BlogNone(string title, Guid? shadow, bool dummy, int id)'; cannot bind 'dummy', 'description' in 'BlogNone(string title, Guid? shadow, bool dummy, int id, string description)'. Note that only mapped properties can be bound to constructor parameters. Navigations to related entities, including references to owned types, cannot be bound.

Fixes #26341

> The 'DateOnly' property 'Blog.PostedOn' could not be mapped because the database provider does not support this type. Consider converting the property value to a type supported by the database using a value converter. See https://aka.ms/efcore-docs-value-converters for more information. Alternately, exclude the property from the model using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

Or if the store type is specified:

> The 'DateOnly' property 'Blog.PostedOn' could not be mapped to the database type 'datetime2' because the database provider does not support mapping 'DateOnly' properties to 'datetime2' columns. Consider mapping to a different database type or converting the property value to a type supported by the database using a value converter. See https://aka.ms/efcore-docs-value-converters for more information. Alternately, exclude the property from the model using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

Fixes #21954

> Cannot save instance of 'Skinner' because it is an owned entity without any reference to its owner. Owned entities can only be saved as part of an aggregate also including the owner entity.
@ajcvickers ajcvickers modified the milestones: 7.0.0, 7.0.0-preview1 Feb 14, 2022
@ajcvickers ajcvickers modified the milestones: 7.0.0-preview1, 7.0.0 Nov 5, 2022
@ajcvickers ajcvickers removed their assignment Sep 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-change-tracking closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants