dotnet / dotnet/EntityFramework.Docs

Document the dangers of using a navigation property to compute the value of a mapped scalar property

Open
#2,620 5 comments 0 reactions 0 assignees View on GitHub
area-model-building
Dominant language
Mermaid
Stars
1.7k
Forks
2k
Avg merge
7d 23h
Merged PRs (30d)
16

Description

Storing computed property explained in [issue-18998](https://github.com/dotnet/efcore/issues/18998)

But if the computed property dependent on `List Models` which configured as OwnMany, `Models.Clear()` does not update the computed property.

code sample:
```csharp

class Program
{
static async Task Main(string[] args)
{
//Arrange
var seed = new Blog
{
Posts = new List
{
new Post {Title = "one"},
new Post {Title = "two"},
}
};

await using (var ctx = new BlogContext())
{
await ctx.Database.EnsureDeletedAsync();
await ctx.Database.EnsureCreatedAsync();

ctx.Blogs.Add(seed);

ctx.SaveChanges();
}

//Act + Assert
await using (var ctx = new BlogContext())
{
var blog = await ctx.Blogs.FindAsync(seed.Id);

Console.WriteLine(blog.HasPosts); //true

blog.Posts.Clear(); //changing here

Console.WriteLine(blog.HasPosts); //false

var isHasPostsModified =
ctx.ChangeTracker.Entries().Single().Property(p => p.HasPosts).IsModified;

Console.WriteLine(isHasPostsModified); //false, but should be true!

//DELETE FROM "Post"
//WHERE "BlogId" = @p0 AND "Id" = @p1;
//DELETE FROM "Post"
//WHERE "BlogId" = @p2 AND "Id" = @p3;
ctx.SaveChanges(); //No UPDATE HasPosts Statemet!
}
}

public class BlogContext : DbContext
{
public DbSet Blogs { get; set; }

static ILoggerFactory ContextLoggerFactory
=> LoggerFactory.Create(b => b.AddConsole().AddFilter("", LogLevel.Information));

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseNpgsql(@"Host=localhost;Username=test;Password=test")
//.UseInMemoryDatabase("dbName");
.EnableSensitiveDataLogging()
.UseLoggerFactory(ContextLoggerFactory);

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity().Property(b => b.Id);
modelBuilder.Entity().HasKey(b => b.Id);

//https://github.com/dotnet/efcore/issues/18998
modelBuilder.Entity()
.Property(r => r.HasPosts)
.UsePropertyAccessMode(PropertyAccessMode.Property);

modelBuilder.Entity().OwnsMany(b => b.Posts,
builder => builder.Property(p => p.Title));
}
}

public class Blog
{
public int Id { get; set; }

public bool HasPosts
{
get => Posts != null && Posts.Any();

private set { } // https://github.com/dotnet/efcore/issues/13316
}

public List Posts { get; set; }
}

public class Post
{
public string Title { get; set; }
}
}

```

EF Core version:
Database provider: approved on Microsoft.EntityFrameworkCore.InMemory / PostgreSQL

```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.