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

Changing the reference of an owned type to null is not saved #20558

Closed
mark-glass opened this issue Apr 7, 2020 · 3 comments
Closed

Changing the reference of an owned type to null is not saved #20558

mark-glass opened this issue Apr 7, 2020 · 3 comments
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported

Comments

@mark-glass
Copy link

Hello everbody,

Statement of the problem

I am quite new to EntityFramework but I guess I am encountering a problem when updating a reference of an owned type, that is not null, to null. This update is just not saved to the SQLite file.
This problem appears only in the case of a disconnected entity.
It is correctly tracked/saved if the entity is loaded and updated within a single context.

Please find below a minimal program demonstrating the problem.

Minimal program

using Microsoft.EntityFrameworkCore;
using System;

namespace ef_owned_null_test
{
  /// <summary>
  /// Some entity with string fields and an owned object
  /// </summary>
  public class SomeEntity
  {
    public string Name { get; private set; }
    public SomeOwnedType OwnedType { get; set; }

    public int Id { get; private set; }
    private SomeEntity()
    {
    }

    public SomeEntity(string name, SomeOwnedType stackerParameters)
    {
      Name = name;
      OwnedType = stackerParameters;
    }
  }

  /// <summary>
  /// This object is owned by the entity and has some int fields
  /// </summary>
  public class SomeOwnedType
  {
    public int Depth { get; set; }

    public SomeOwnedType(int depth)
    {
      Depth = depth;
    }
  }

  public class MyContext : DbContext
  {
    public MyContext() : base()
    {
      this.Database.EnsureCreated();
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
      optionsBuilder.UseSqlite("Data Source=myfile.db;").EnableSensitiveDataLogging();
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {

      modelBuilder.Entity<SomeEntity>(cb =>
      {
        cb.UsePropertyAccessMode(PropertyAccessMode.Property);
        cb.Property(p => p.Name).IsRequired();
        cb.HasIndex(p => p.Name).IsUnique();
        cb.OwnsOne(p => p.OwnedType, cb =>
          {
            cb.UsePropertyAccessMode(PropertyAccessMode.Property);
            cb.Property(p => p.Depth);
          });
      });
    }

    public DbSet<SomeEntity> Entities { get; set; }
  }

  class Program
  {
    static void Main(string[] args)
    {
      var entity = new SomeEntity("a name" + Guid.NewGuid().ToString(), new SomeOwnedType(10));

      using (var context = new MyContext())
      {
        context.Add(entity);
        context.SaveChanges();
      }

      // Update the entities' reference while it is disconnected
      entity.OwnedType = null; 

      using (var context = new MyContext())
      {
        var entityEntry = context.Entities.Update(entity);
        Console.WriteLine($"Entity state: {entityEntry.State}");
        context.SaveChanges(); // No exception but not saved to SQLite file
      }
    }
  }
}

Technical information

Microsoft.EntityFrameworkCore.Sqlite 3.1.3
Windows: 10
Visual Studio Version 16.4.6
Target framework: .NET core 3.1

@ajcvickers
Copy link
Member

@mark-glass In this case, EF can't tell the difference between the reference being null because it was always null, and the reference being null because it was non-null and then set to null. See the documentation for disconnected entities.

@mark-glass
Copy link
Author

Thank you for your prompt reply and thank you for the link to the documentation.

In fact I had read the documentation before posting but it seems I missed the point. I thought I am in the scenario "Saving single entities"

If it is known whether or not an insert or update is needed, then either Add or Update can be used appropriately

and that by calling context.Update explicitly I tell EF that my entity has changed and that EF will find out the changes.
If for instance in the code above my reference was a value type, i.e. if I make the entites' field OwnedType to an integer, then EF recognizes the change and updates the sqlite db with the second context.SaveChanges.

In our real program we have a repository that reads the sqlite content in a context at program start and when the repository is saved it opens a new context and calls its Add,Update,Delete for some entities explicitly.

If this non-recognition of the change of the reference for a disconnected entity is intented behavior of EF is there maybe any other way to tell EF that my entity changed? Do I have to tell EF explicitly that the reference was updated to null?

@ajcvickers
Copy link
Member

@mark-glass I think the main issue you're running into is that owned types do not behave like value objects in many situations. See the discussion on this comment and the issues linked from #13947. So you will, in general, need to treat owned entities like other entities in this case--that is, you're dealing with a disconnected graph of entities, not the single entity case.

@ajcvickers ajcvickers added closed-no-further-action The issue is closed and no further action is planned. customer-reported labels Apr 13, 2020
@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported
Projects
None yet
Development

No branches or pull requests

2 participants