Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/EFCore/Metadata/Internal/PropertyAccessorsFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,18 @@ public static Expression CreateMemberAccess(
break;
}
}
else
else if (!fromDeclaringType
|| !addNullCheck
|| property is not IComplexProperty complexProperty
|| instanceExpression.Type.IsValueType
|| complexProperty.ClrType.IsValueType)
{
// Disable null check for all cases except:
// - fromDeclaringType is true AND
// - addNullCheck is true AND
// - property is a complex property AND
// - instance is a reference type AND
// - complex property type is a reference type
addNullCheck = false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,102 @@ public class ComplexTypesTrackingSqlServerTest(
ITestOutputHelper testOutputHelper)
: ComplexTypesTrackingSqlServerTestBase<ComplexTypesTrackingSqlServerTest.SqlServerFixture>(fixture, testOutputHelper)
{
[ConditionalFact]
public virtual async Task Can_read_original_values_with_TPH_shared_complex_property_column_null()
{
await using var context = CreateContext();

await context.Database.CreateExecutionStrategy().ExecuteAsync(
context,
async context =>
{
await using var transaction = await context.Database.BeginTransactionAsync();

context.Add(new InheritedItem1 { Name = "Item1" });
await context.SaveChangesAsync();

context.ChangeTracker.Clear();
var item = await context.Set<InheritedItemBase>().FirstAsync();
var entry = context.ChangeTracker.Entries().First();
var originalItem = (InheritedItemBase)entry.OriginalValues.ToObject();

Assert.NotNull(originalItem);
Assert.Equal("Item1", originalItem.Name);
});
}

[ConditionalFact]
public virtual async Task Can_read_original_values_with_TPH_shared_complex_property_column_with_value()
{
await using var context = CreateContext();

await context.Database.CreateExecutionStrategy().ExecuteAsync(
context,
async context =>
{
await using var transaction = await context.Database.BeginTransactionAsync();

context.Add(new InheritedItem1 { Name = "Item1", SharedPrice = new SharedPrice { Amount = "10.99" } });
await context.SaveChangesAsync();

context.ChangeTracker.Clear();
var item = await context.Set<InheritedItem1>().FirstAsync();
var entry = context.ChangeTracker.Entries().First();
var originalItem = (InheritedItemBase)entry.OriginalValues.ToObject();

Assert.NotNull(originalItem);
Assert.Equal("Item1", originalItem.Name);
var item1 = Assert.IsType<InheritedItem1>(originalItem);
Assert.NotNull(item1.SharedPrice);
Assert.Equal("10.99", item1.SharedPrice.Amount);
});
}

public class SqlServerFixture : SqlServerFixtureBase
{
protected override string StoreName
=> nameof(ComplexTypesTrackingSqlServerTest);

protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context)
{
base.OnModelCreating(modelBuilder, context);

modelBuilder.Entity<InheritedItemBase>().HasDiscriminator<string>("Discriminator")
.HasValue<InheritedItem1>("Item1")
.HasValue<InheritedItem2>("Item2");

modelBuilder.Entity<InheritedItem1>().ComplexProperty(
x => x.SharedPrice,
p => p.Property(a => a.Amount).HasColumnName("SharedPriceAmount"));

modelBuilder.Entity<InheritedItem2>().ComplexProperty(
x => x.SharedPrice,
p => p.Property(a => a.Amount).HasColumnName("SharedPriceAmount"));
}
}
}

public abstract class InheritedItemBase
{
public int Id { get; set; }
public required string Name { get; set; }
}

public class InheritedItem1 : InheritedItemBase
{
public SharedPrice? SharedPrice { get; set; }
}

public class InheritedItem2 : InheritedItemBase
{
public SharedPrice? SharedPrice { get; set; }
}

public class SharedPrice
{
public required string Amount { get; init; }
}

public class ComplexTypesTrackingProxiesSqlServerTest(
ComplexTypesTrackingProxiesSqlServerTest.SqlServerFixture fixture,
ITestOutputHelper testOutputHelper)
Expand Down
Loading