Skip to content

Commit ca3beb1

Browse files
committed
.Net 10
1 parent 41495cb commit ca3beb1

4 files changed

Lines changed: 181 additions & 1 deletion

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace EntityFrameworkCore.SqlServer.SimpleBulks.Tests.Database;
2+
3+
public class JsonOwnedTypeOrder
4+
{
5+
public int Id { get; set; }
6+
7+
public OwnedTypeAddress ShippingAddress { get; set; }
8+
}

src/EntityFrameworkCore.SqlServer.SimpleBulks.Tests/Database/TestDbContext.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ public class TestDbContext : DbContext
2323

2424
public DbSet<JsonComplexTypeOrder> JsonComplexTypeOrders { get; set; }
2525

26+
public DbSet<JsonOwnedTypeOrder> JsonOwnedTypeOrders { get; set; }
27+
2628
public DbSet<Blog> Blogs { get; set; }
2729

2830
public DbSet<RssBlog> RssBlogs { get; set; }
@@ -71,6 +73,16 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
7173
});
7274
});
7375

76+
modelBuilder.Entity<JsonOwnedTypeOrder>().OwnsOne(x => x.ShippingAddress, x =>
77+
{
78+
x.ToJson();
79+
//x.ToJson("xxx").HasColumnType("json");
80+
x.OwnsOne(y => y.Location, y =>
81+
{
82+
y.HasJsonPropertyName("xxx");
83+
});
84+
});
85+
7486
base.OnModelCreating(modelBuilder);
7587
}
7688
}

src/EntityFrameworkCore.SqlServer.SimpleBulks.Tests/DbContextExtensions/GetPropertiesTests.cs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,4 +385,91 @@ private static void WriteObject(Utf8JsonWriter writer, object obj, IReadOnlyList
385385

386386
writer.WriteEndObject();
387387
}
388+
389+
[Fact]
390+
public void GetProperties_JsonOwnedType_ReturnsCorrectColumnInformation()
391+
{
392+
// Arrange
393+
var dbContext = new TestDbContext("", "");
394+
395+
// Act
396+
var properties = dbContext.GetProperties(typeof(JsonOwnedTypeOrder));
397+
398+
// Assert
399+
Assert.Equal(2, properties.Count);
400+
401+
var property = properties.First(p => p.PropertyName == "Id");
402+
Assert.Equal(typeof(int), property.PropertyType);
403+
Assert.Equal("Id", property.ColumnName);
404+
Assert.Equal("int", property.ColumnType);
405+
Assert.Equal(ValueGenerated.OnAdd, property.ValueGenerated);
406+
Assert.Null(property.DefaultValueSql);
407+
Assert.True(property.IsPrimaryKey);
408+
Assert.False(property.IsRowVersion);
409+
410+
property = properties.First(p => p.PropertyName == "ShippingAddress");
411+
Assert.Equal(typeof(OwnedTypeAddress), property.PropertyType);
412+
Assert.Equal("ShippingAddress", property.ColumnName);
413+
Assert.Equal("nvarchar(max)", property.ColumnType);
414+
Assert.Equal(ValueGenerated.Never, property.ValueGenerated);
415+
Assert.Null(property.DefaultValueSql);
416+
Assert.False(property.IsPrimaryKey);
417+
Assert.False(property.IsRowVersion);
418+
Assert.True(property.IsJson);
419+
Assert.NotNull(property.JsonPropertyWriters);
420+
421+
// Verify that the JsonPropertyWriters have correct structure
422+
var writers = property.JsonPropertyWriters;
423+
var flattenedWriters = property.GetFlattenedJsonPropertyWriters();
424+
Assert.Equal(3, writers.Count); // Street and Location
425+
426+
var streetWriter = writers.FirstOrDefault(w => w.ClrPropertyName == "Street");
427+
Assert.NotNull(streetWriter);
428+
Assert.Equal("Street", streetWriter.JsonPropertyName);
429+
Assert.Equal("Street", streetWriter.FullJsonPath);
430+
Assert.Equal("Street", streetWriter.FullClrPropertyName);
431+
Assert.Equal(typeof(string), streetWriter.PropertyType);
432+
Assert.False(streetWriter.IsNestedComplexType);
433+
434+
var locationWriter = writers.FirstOrDefault(w => w.ClrPropertyName == "Location");
435+
Assert.NotNull(locationWriter);
436+
Assert.Equal("xxx", locationWriter.JsonPropertyName); // Mapped to "xxx" in TestDbContext
437+
Assert.Equal("xxx", locationWriter.FullJsonPath);
438+
Assert.Equal("Location", locationWriter.FullClrPropertyName);
439+
Assert.Equal(typeof(OwnedTypeLocation), locationWriter.PropertyType);
440+
Assert.True(locationWriter.IsNestedComplexType);
441+
Assert.NotNull(locationWriter.NestedProperties);
442+
Assert.Equal(3, locationWriter.NestedProperties.Count); // Lat and Lng
443+
444+
var latWriter = locationWriter.NestedProperties.FirstOrDefault(w => w.ClrPropertyName == "Lat");
445+
Assert.NotNull(latWriter);
446+
Assert.Equal("xxx.Lat", latWriter.FullJsonPath);
447+
Assert.Equal("Location.Lat", latWriter.FullClrPropertyName);
448+
Assert.Equal(typeof(double), latWriter.PropertyType);
449+
450+
var lngWriter = locationWriter.NestedProperties.FirstOrDefault(w => w.ClrPropertyName == "Lng");
451+
Assert.NotNull(lngWriter);
452+
Assert.Equal("xxx.Lng", lngWriter.FullJsonPath);
453+
Assert.Equal("Location.Lng", lngWriter.FullClrPropertyName);
454+
Assert.Equal(typeof(double), lngWriter.PropertyType);
455+
456+
// Verify serialization using JsonPropertyWriters
457+
var testAddress = new OwnedTypeAddress
458+
{
459+
Street = "123 Main St",
460+
Location = new OwnedTypeLocation
461+
{
462+
Lat = 40.7128,
463+
Lng = -74.0060
464+
}
465+
};
466+
467+
var json = SerializeWithJsonPropertyWriters(testAddress, writers);
468+
Assert.NotNull(json);
469+
Assert.Contains("Street", json);
470+
Assert.Contains("123 Main St", json);
471+
Assert.Contains("xxx", json); // Location is mapped to "xxx"
472+
Assert.Contains("Lat", json);
473+
Assert.Contains("Lng", json);
474+
}
388475
}

src/EntityFrameworkCore.SqlServer.SimpleBulks/Extensions/DbContextExtensions.cs

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ public static IReadOnlyList<ColumnInfor> GetProperties(this DbContext dbContext,
152152

153153
if (ownedProperty.TargetEntityType.IsMappedToJson())
154154
{
155-
155+
// For owned entities mapped to JSON, add the owned navigation itself as a single JSON column
156+
AddJsonOwnedProperty(data, ownedProperty);
156157
}
157158
else
158159
{
@@ -256,6 +257,78 @@ private static List<JsonPropertyWriter> BuildJsonPropertyWriters(IComplexType co
256257
return writers;
257258
}
258259

260+
private static List<JsonPropertyWriter> BuildJsonPropertyWriters(IEntityType entityType, string clrPrefix = "", string jsonPrefix = "")
261+
{
262+
var writers = new List<JsonPropertyWriter>();
263+
264+
// Add writers for scalar properties on the owned entity type
265+
foreach (var property in entityType.GetProperties())
266+
{
267+
var jsonPropertyName = property.GetJsonPropertyName() ?? property.Name;
268+
var readerWriter = property.GetJsonValueReaderWriter() ?? property.GetTypeMapping().JsonValueReaderWriter;
269+
270+
writers.Add(new JsonPropertyWriter
271+
{
272+
JsonPropertyName = jsonPropertyName,
273+
ClrPropertyName = property.Name,
274+
FullJsonPath = string.IsNullOrEmpty(jsonPrefix) ? jsonPropertyName : $"{jsonPrefix}.{jsonPropertyName}",
275+
FullClrPropertyName = string.IsNullOrEmpty(clrPrefix) ? property.Name : $"{clrPrefix}.{property.Name}",
276+
PropertyType = property.ClrType,
277+
ReaderWriter = readerWriter,
278+
NestedProperties = null
279+
});
280+
}
281+
282+
var ownedProperties = entityType.GetNavigations().Where(n => n.TargetEntityType.IsOwned());
283+
284+
// Add writers for complex properties on the owned entity type
285+
foreach (var nestedOwnedProperty in ownedProperties)
286+
{
287+
// For complex properties mapped to JSON inside the owned entity, add a single JSON writer
288+
var jsonPropertyName = nestedOwnedProperty.TargetEntityType.GetJsonPropertyName() ?? nestedOwnedProperty.Name;
289+
var fullJsonPath = string.IsNullOrEmpty(jsonPrefix) ? jsonPropertyName : $"{jsonPrefix}.{jsonPropertyName}";
290+
var fullClrPropertyName = string.IsNullOrEmpty(clrPrefix) ? nestedOwnedProperty.Name : $"{clrPrefix}.{nestedOwnedProperty.Name}";
291+
292+
var nestedWriters = BuildJsonPropertyWriters(nestedOwnedProperty.TargetEntityType, fullClrPropertyName, fullJsonPath);
293+
294+
writers.Add(new JsonPropertyWriter
295+
{
296+
JsonPropertyName = jsonPropertyName,
297+
ClrPropertyName = nestedOwnedProperty.Name,
298+
FullJsonPath = fullJsonPath,
299+
FullClrPropertyName = fullClrPropertyName,
300+
PropertyType = nestedOwnedProperty.ClrType,
301+
ReaderWriter = null,
302+
NestedProperties = nestedWriters
303+
});
304+
}
305+
306+
return writers;
307+
}
308+
309+
private static void AddJsonOwnedProperty(List<ColumnInfor> columnInfors, INavigation ownedNavigation)
310+
{
311+
var containerColumnName = ownedNavigation.TargetEntityType.GetContainerColumnName();
312+
var containerColumnType = ownedNavigation.TargetEntityType.GetContainerColumnType() ?? "nvarchar(max)";
313+
314+
var jsonPropertyWriters = BuildJsonPropertyWriters(ownedNavigation.TargetEntityType);
315+
316+
columnInfors.Add(new ColumnInfor
317+
{
318+
PropertyName = ownedNavigation.Name,
319+
PropertyType = ownedNavigation.TargetEntityType.ClrType,
320+
ColumnName = containerColumnName,
321+
ColumnType = containerColumnType,
322+
ValueGenerated = ValueGenerated.Never,
323+
DefaultValueSql = null,
324+
IsPrimaryKey = false,
325+
IsRowVersion = false,
326+
ValueConverter = null,
327+
IsJson = true,
328+
JsonPropertyWriters = jsonPropertyWriters
329+
});
330+
}
331+
259332
private static void AddComplexProperty(List<ColumnInfor> columnInfors, IComplexProperty complexProperty, StoreObjectIdentifier storeObjectIdentifier, string prefix = "")
260333
{
261334
var entityProperties = complexProperty.ComplexType.GetProperties();

0 commit comments

Comments
 (0)