@@ -1467,6 +1467,296 @@ protected virtual void BuildModelNotICollection(ModelBuilder modelBuilder)
1467
1467
1468
1468
#endregion
1469
1469
1470
+ #region BadJsonProperties
1471
+
1472
+ [ ConditionalFact ]
1473
+ public virtual async Task Bad_json_properties_duplicated_navigations_tracking ( )
1474
+ {
1475
+ var contextFactory = await InitializeAsync < ContextBadJsonProperties > (
1476
+ onModelCreating : BuildModelBadJsonProperties ,
1477
+ onConfiguring : b => b . ConfigureWarnings ( ConfigureWarnings ) ,
1478
+ seed : SeedBadJsonProperties ) ;
1479
+
1480
+ using ( var context = contextFactory . CreateContext ( ) )
1481
+ {
1482
+ var baseline = await context . Entities . SingleAsync ( x => x . Scenario == "baseline" ) ;
1483
+ var dupNavs = await context . Entities . SingleAsync ( x => x . Scenario == "duplicated navigations" ) ;
1484
+
1485
+ // for tracking, first one wins
1486
+ Assert . Equal ( baseline . RequiredReference . NestedOptional . Text , dupNavs . RequiredReference . NestedOptional . Text ) ;
1487
+ Assert . Equal ( baseline . RequiredReference . NestedRequired . Text , dupNavs . RequiredReference . NestedRequired . Text ) ;
1488
+ Assert . Equal ( baseline . RequiredReference . NestedCollection [ 0 ] . Text , dupNavs . RequiredReference . NestedCollection [ 0 ] . Text ) ;
1489
+ Assert . Equal ( baseline . RequiredReference . NestedCollection [ 1 ] . Text , dupNavs . RequiredReference . NestedCollection [ 1 ] . Text ) ;
1490
+
1491
+ Assert . Equal ( baseline . OptionalReference . NestedOptional . Text , dupNavs . OptionalReference . NestedOptional . Text ) ;
1492
+ Assert . Equal ( baseline . OptionalReference . NestedRequired . Text , dupNavs . OptionalReference . NestedRequired . Text ) ;
1493
+ Assert . Equal ( baseline . OptionalReference . NestedCollection [ 0 ] . Text , dupNavs . OptionalReference . NestedCollection [ 0 ] . Text ) ;
1494
+ Assert . Equal ( baseline . OptionalReference . NestedCollection [ 1 ] . Text , dupNavs . OptionalReference . NestedCollection [ 1 ] . Text ) ;
1495
+
1496
+ Assert . Equal ( baseline . Collection [ 0 ] . NestedOptional . Text , dupNavs . Collection [ 0 ] . NestedOptional . Text ) ;
1497
+ Assert . Equal ( baseline . Collection [ 0 ] . NestedRequired . Text , dupNavs . Collection [ 0 ] . NestedRequired . Text ) ;
1498
+ Assert . Equal ( baseline . Collection [ 0 ] . NestedCollection [ 0 ] . Text , dupNavs . Collection [ 0 ] . NestedCollection [ 0 ] . Text ) ;
1499
+ Assert . Equal ( baseline . Collection [ 0 ] . NestedCollection [ 1 ] . Text , dupNavs . Collection [ 0 ] . NestedCollection [ 1 ] . Text ) ;
1500
+
1501
+ Assert . Equal ( baseline . Collection [ 1 ] . NestedOptional . Text , dupNavs . Collection [ 1 ] . NestedOptional . Text ) ;
1502
+ Assert . Equal ( baseline . Collection [ 1 ] . NestedRequired . Text , dupNavs . Collection [ 1 ] . NestedRequired . Text ) ;
1503
+ Assert . Equal ( baseline . Collection [ 1 ] . NestedCollection [ 0 ] . Text , dupNavs . Collection [ 1 ] . NestedCollection [ 0 ] . Text ) ;
1504
+ Assert . Equal ( baseline . Collection [ 1 ] . NestedCollection [ 1 ] . Text , dupNavs . Collection [ 1 ] . NestedCollection [ 1 ] . Text ) ;
1505
+ }
1506
+ }
1507
+
1508
+ [ ConditionalFact ]
1509
+ public virtual async Task Bad_json_properties_duplicated_navigations_no_tracking ( )
1510
+ {
1511
+ var contextFactory = await InitializeAsync < ContextBadJsonProperties > (
1512
+ onModelCreating : BuildModelBadJsonProperties ,
1513
+ onConfiguring : b => b . ConfigureWarnings ( ConfigureWarnings ) ,
1514
+ seed : SeedBadJsonProperties ) ;
1515
+
1516
+ using ( var context = contextFactory . CreateContext ( ) )
1517
+ {
1518
+ var query = context . Entities . AsNoTracking ( ) ;
1519
+
1520
+ var baseline = query . Single ( x => x . Scenario == "baseline" ) ;
1521
+ var dupNavs = query . Single ( x => x . Scenario == "duplicated navigations" ) ;
1522
+
1523
+ // for no tracking, last one wins
1524
+ Assert . Equal ( baseline . RequiredReference . NestedOptional . Text + " dupnav" , dupNavs . RequiredReference . NestedOptional . Text ) ;
1525
+ Assert . Equal ( baseline . RequiredReference . NestedRequired . Text + " dupnav" , dupNavs . RequiredReference . NestedRequired . Text ) ;
1526
+ Assert . Equal ( baseline . RequiredReference . NestedCollection [ 0 ] . Text + " dupnav" , dupNavs . RequiredReference . NestedCollection [ 0 ] . Text ) ;
1527
+ Assert . Equal ( baseline . RequiredReference . NestedCollection [ 1 ] . Text + " dupnav" , dupNavs . RequiredReference . NestedCollection [ 1 ] . Text ) ;
1528
+
1529
+ Assert . Equal ( baseline . OptionalReference . NestedOptional . Text + " dupnav" , dupNavs . OptionalReference . NestedOptional . Text ) ;
1530
+ Assert . Equal ( baseline . OptionalReference . NestedRequired . Text + " dupnav" , dupNavs . OptionalReference . NestedRequired . Text ) ;
1531
+ Assert . Equal ( baseline . OptionalReference . NestedCollection [ 0 ] . Text + " dupnav" , dupNavs . OptionalReference . NestedCollection [ 0 ] . Text ) ;
1532
+ Assert . Equal ( baseline . OptionalReference . NestedCollection [ 1 ] . Text + " dupnav" , dupNavs . OptionalReference . NestedCollection [ 1 ] . Text ) ;
1533
+
1534
+ Assert . Equal ( baseline . Collection [ 0 ] . NestedOptional . Text + " dupnav" , dupNavs . Collection [ 0 ] . NestedOptional . Text ) ;
1535
+ Assert . Equal ( baseline . Collection [ 0 ] . NestedRequired . Text + " dupnav" , dupNavs . Collection [ 0 ] . NestedRequired . Text ) ;
1536
+ Assert . Equal ( baseline . Collection [ 0 ] . NestedCollection [ 0 ] . Text + " dupnav" , dupNavs . Collection [ 0 ] . NestedCollection [ 0 ] . Text ) ;
1537
+ Assert . Equal ( baseline . Collection [ 0 ] . NestedCollection [ 1 ] . Text + " dupnav" , dupNavs . Collection [ 0 ] . NestedCollection [ 1 ] . Text ) ;
1538
+
1539
+ Assert . Equal ( baseline . Collection [ 1 ] . NestedOptional . Text + " dupnav" , dupNavs . Collection [ 1 ] . NestedOptional . Text ) ;
1540
+ Assert . Equal ( baseline . Collection [ 1 ] . NestedRequired . Text + " dupnav" , dupNavs . Collection [ 1 ] . NestedRequired . Text ) ;
1541
+ Assert . Equal ( baseline . Collection [ 1 ] . NestedCollection [ 0 ] . Text + " dupnav" , dupNavs . Collection [ 1 ] . NestedCollection [ 0 ] . Text ) ;
1542
+ Assert . Equal ( baseline . Collection [ 1 ] . NestedCollection [ 1 ] . Text + " dupnav" , dupNavs . Collection [ 1 ] . NestedCollection [ 1 ] . Text ) ;
1543
+ }
1544
+ }
1545
+
1546
+ [ ConditionalTheory ]
1547
+ [ InlineData ( true ) ]
1548
+ [ InlineData ( false ) ]
1549
+ public virtual async Task Bad_json_properties_duplicated_scalars ( bool noTracking )
1550
+ {
1551
+ var contextFactory = await InitializeAsync < ContextBadJsonProperties > (
1552
+ onModelCreating : BuildModelBadJsonProperties ,
1553
+ onConfiguring : b => b . ConfigureWarnings ( ConfigureWarnings ) ,
1554
+ seed : SeedBadJsonProperties ) ;
1555
+
1556
+ using ( var context = contextFactory . CreateContext ( ) )
1557
+ {
1558
+ var query = noTracking ? context . Entities . AsNoTracking ( ) : context . Entities ;
1559
+
1560
+ var baseline = await query . SingleAsync ( x => x . Scenario == "baseline" ) ;
1561
+ var dupProps = await query . SingleAsync ( x => x . Scenario == "duplicated scalars" ) ;
1562
+
1563
+ Assert . Equal ( baseline . RequiredReference . NestedOptional . Text + " dupprop" , dupProps . RequiredReference . NestedOptional . Text ) ;
1564
+ Assert . Equal ( baseline . RequiredReference . NestedRequired . Text + " dupprop" , dupProps . RequiredReference . NestedRequired . Text ) ;
1565
+ Assert . Equal ( baseline . RequiredReference . NestedCollection [ 0 ] . Text + " dupprop" , dupProps . RequiredReference . NestedCollection [ 0 ] . Text ) ;
1566
+ Assert . Equal ( baseline . RequiredReference . NestedCollection [ 1 ] . Text + " dupprop" , dupProps . RequiredReference . NestedCollection [ 1 ] . Text ) ;
1567
+
1568
+ Assert . Equal ( baseline . OptionalReference . NestedOptional . Text + " dupprop" , dupProps . OptionalReference . NestedOptional . Text ) ;
1569
+ Assert . Equal ( baseline . OptionalReference . NestedRequired . Text + " dupprop" , dupProps . OptionalReference . NestedRequired . Text ) ;
1570
+ Assert . Equal ( baseline . OptionalReference . NestedCollection [ 0 ] . Text + " dupprop" , dupProps . OptionalReference . NestedCollection [ 0 ] . Text ) ;
1571
+ Assert . Equal ( baseline . OptionalReference . NestedCollection [ 1 ] . Text + " dupprop" , dupProps . OptionalReference . NestedCollection [ 1 ] . Text ) ;
1572
+
1573
+ Assert . Equal ( baseline . Collection [ 0 ] . NestedOptional . Text + " dupprop" , dupProps . Collection [ 0 ] . NestedOptional . Text ) ;
1574
+ Assert . Equal ( baseline . Collection [ 0 ] . NestedRequired . Text + " dupprop" , dupProps . Collection [ 0 ] . NestedRequired . Text ) ;
1575
+ Assert . Equal ( baseline . Collection [ 0 ] . NestedCollection [ 0 ] . Text + " dupprop" , dupProps . Collection [ 0 ] . NestedCollection [ 0 ] . Text ) ;
1576
+ Assert . Equal ( baseline . Collection [ 0 ] . NestedCollection [ 1 ] . Text + " dupprop" , dupProps . Collection [ 0 ] . NestedCollection [ 1 ] . Text ) ;
1577
+
1578
+ Assert . Equal ( baseline . Collection [ 1 ] . NestedOptional . Text + " dupprop" , dupProps . Collection [ 1 ] . NestedOptional . Text ) ;
1579
+ Assert . Equal ( baseline . Collection [ 1 ] . NestedRequired . Text + " dupprop" , dupProps . Collection [ 1 ] . NestedRequired . Text ) ;
1580
+ Assert . Equal ( baseline . Collection [ 1 ] . NestedCollection [ 0 ] . Text + " dupprop" , dupProps . Collection [ 1 ] . NestedCollection [ 0 ] . Text ) ;
1581
+ Assert . Equal ( baseline . Collection [ 1 ] . NestedCollection [ 1 ] . Text + " dupprop" , dupProps . Collection [ 1 ] . NestedCollection [ 1 ] . Text ) ;
1582
+ }
1583
+ }
1584
+
1585
+ [ ConditionalTheory ]
1586
+ [ InlineData ( true ) ]
1587
+ [ InlineData ( false ) ]
1588
+ public virtual async Task Bad_json_properties_empty_navigations ( bool noTracking )
1589
+ {
1590
+ var contextFactory = await InitializeAsync < ContextBadJsonProperties > (
1591
+ onModelCreating : BuildModelBadJsonProperties ,
1592
+ onConfiguring : b => b . ConfigureWarnings ( ConfigureWarnings ) ,
1593
+ seed : SeedBadJsonProperties ) ;
1594
+
1595
+ using ( var context = contextFactory . CreateContext ( ) )
1596
+ {
1597
+ var query = noTracking ? context . Entities . AsNoTracking ( ) : context . Entities ;
1598
+ var emptyNavs = await query . SingleAsync ( x => x . Scenario == "empty navigation property names" ) ;
1599
+
1600
+ Assert . Null ( emptyNavs . RequiredReference . NestedOptional ) ;
1601
+ Assert . Null ( emptyNavs . RequiredReference . NestedRequired ) ;
1602
+ Assert . Null ( emptyNavs . RequiredReference . NestedCollection ) ;
1603
+
1604
+ Assert . Null ( emptyNavs . OptionalReference . NestedOptional ) ;
1605
+ Assert . Null ( emptyNavs . OptionalReference . NestedRequired ) ;
1606
+ Assert . Null ( emptyNavs . OptionalReference . NestedCollection ) ;
1607
+
1608
+ Assert . Null ( emptyNavs . Collection [ 0 ] . NestedOptional ) ;
1609
+ Assert . Null ( emptyNavs . Collection [ 0 ] . NestedRequired ) ;
1610
+ Assert . Null ( emptyNavs . Collection [ 0 ] . NestedCollection ) ;
1611
+
1612
+ Assert . Null ( emptyNavs . Collection [ 1 ] . NestedOptional ) ;
1613
+ Assert . Null ( emptyNavs . Collection [ 1 ] . NestedRequired ) ;
1614
+ Assert . Null ( emptyNavs . Collection [ 1 ] . NestedCollection ) ;
1615
+ }
1616
+ }
1617
+
1618
+ [ ConditionalTheory ]
1619
+ [ InlineData ( true ) ]
1620
+ [ InlineData ( false ) ]
1621
+ public virtual async Task Bad_json_properties_empty_scalars ( bool noTracking )
1622
+ {
1623
+ var contextFactory = await InitializeAsync < ContextBadJsonProperties > (
1624
+ onModelCreating : BuildModelBadJsonProperties ,
1625
+ onConfiguring : b => b . ConfigureWarnings ( ConfigureWarnings ) ,
1626
+ seed : SeedBadJsonProperties ) ;
1627
+
1628
+ using ( var context = contextFactory . CreateContext ( ) )
1629
+ {
1630
+ var query = noTracking ? context . Entities . AsNoTracking ( ) : context . Entities ;
1631
+ var emptyNavs = await query . SingleAsync ( x => x . Scenario == "empty scalar property names" ) ;
1632
+
1633
+ Assert . Null ( emptyNavs . RequiredReference . NestedOptional . Text ) ;
1634
+ Assert . Null ( emptyNavs . RequiredReference . NestedRequired . Text ) ;
1635
+ Assert . Null ( emptyNavs . RequiredReference . NestedCollection [ 0 ] . Text ) ;
1636
+ Assert . Null ( emptyNavs . RequiredReference . NestedCollection [ 1 ] . Text ) ;
1637
+
1638
+ Assert . Null ( emptyNavs . OptionalReference . NestedOptional . Text ) ;
1639
+ Assert . Null ( emptyNavs . OptionalReference . NestedRequired . Text ) ;
1640
+ Assert . Null ( emptyNavs . OptionalReference . NestedCollection [ 0 ] . Text ) ;
1641
+ Assert . Null ( emptyNavs . OptionalReference . NestedCollection [ 1 ] . Text ) ;
1642
+
1643
+ Assert . Null ( emptyNavs . Collection [ 0 ] . NestedOptional . Text ) ;
1644
+ Assert . Null ( emptyNavs . Collection [ 0 ] . NestedRequired . Text ) ;
1645
+ Assert . Null ( emptyNavs . Collection [ 0 ] . NestedCollection [ 0 ] . Text ) ;
1646
+ Assert . Null ( emptyNavs . Collection [ 0 ] . NestedCollection [ 1 ] . Text ) ;
1647
+
1648
+ Assert . Null ( emptyNavs . Collection [ 1 ] . NestedOptional . Text ) ;
1649
+ Assert . Null ( emptyNavs . Collection [ 1 ] . NestedRequired . Text ) ;
1650
+ Assert . Null ( emptyNavs . Collection [ 1 ] . NestedCollection [ 0 ] . Text ) ;
1651
+ Assert . Null ( emptyNavs . Collection [ 1 ] . NestedCollection [ 1 ] . Text ) ;
1652
+ }
1653
+ }
1654
+
1655
+ [ ConditionalTheory ]
1656
+ [ InlineData ( true ) ]
1657
+ [ InlineData ( false ) ]
1658
+ public virtual async Task Bad_json_properties_null_navigations ( bool noTracking )
1659
+ {
1660
+ var contextFactory = await InitializeAsync < ContextBadJsonProperties > (
1661
+ onModelCreating : BuildModelBadJsonProperties ,
1662
+ onConfiguring : b => b . ConfigureWarnings ( ConfigureWarnings ) ,
1663
+ seed : SeedBadJsonProperties ) ;
1664
+
1665
+ using ( var context = contextFactory . CreateContext ( ) )
1666
+ {
1667
+ var query = noTracking ? context . Entities . AsNoTracking ( ) : context . Entities ;
1668
+
1669
+ await Assert . ThrowsAnyAsync < JsonException > (
1670
+ ( ) => query . SingleAsync ( x => x . Scenario == "null navigation property names" ) ) ;
1671
+ }
1672
+ }
1673
+
1674
+ [ ConditionalTheory ]
1675
+ [ InlineData ( true ) ]
1676
+ [ InlineData ( false ) ]
1677
+ public virtual async Task Bad_json_properties_null_scalars ( bool noTracking )
1678
+ {
1679
+ var contextFactory = await InitializeAsync < ContextBadJsonProperties > (
1680
+ onModelCreating : BuildModelBadJsonProperties ,
1681
+ onConfiguring : b => b . ConfigureWarnings ( ConfigureWarnings ) ,
1682
+ seed : SeedBadJsonProperties ) ;
1683
+
1684
+ using ( var context = contextFactory . CreateContext ( ) )
1685
+ {
1686
+ var query = noTracking ? context . Entities . AsNoTracking ( ) : context . Entities ;
1687
+
1688
+ var message = ( await Assert . ThrowsAnyAsync < JsonException > (
1689
+ ( ) => query . SingleAsync ( x => x . Scenario == "null scalar property names" ) ) ) . Message ;
1690
+
1691
+ Assert . StartsWith ( "'n' is an invalid start of a property name. Expected a '\" '." , message ) ;
1692
+ }
1693
+ }
1694
+
1695
+ protected class ContextBadJsonProperties ( DbContextOptions options ) : DbContext ( options )
1696
+ {
1697
+ public DbSet < Entity > Entities { get ; set ; }
1698
+
1699
+ public class Entity
1700
+ {
1701
+ public int Id { get ; set ; }
1702
+ public string Scenario { get ; set ; }
1703
+ public JsonRoot OptionalReference { get ; set ; }
1704
+ public JsonRoot RequiredReference { get ; set ; }
1705
+ public List < JsonRoot > Collection { get ; set ; }
1706
+ }
1707
+
1708
+ public class JsonRoot
1709
+ {
1710
+ public JsonBranch NestedRequired { get ; set ; }
1711
+ public JsonBranch NestedOptional { get ; set ; }
1712
+ public List < JsonBranch > NestedCollection { get ; set ; }
1713
+ }
1714
+
1715
+ public class JsonBranch
1716
+ {
1717
+ public string Text { get ; set ; }
1718
+ }
1719
+ }
1720
+
1721
+ protected abstract Task SeedBadJsonProperties ( ContextBadJsonProperties ctx ) ;
1722
+
1723
+ protected virtual void BuildModelBadJsonProperties ( ModelBuilder modelBuilder )
1724
+ => modelBuilder . Entity < ContextBadJsonProperties . Entity > (
1725
+ b =>
1726
+ {
1727
+ b . ToTable ( "Entities" ) ;
1728
+ b . Property ( x => x . Id ) . ValueGeneratedNever ( ) ;
1729
+
1730
+ b . OwnsOne (
1731
+ x => x . RequiredReference , b =>
1732
+ {
1733
+ b . ToJson ( ) . HasColumnType ( JsonColumnType ) ;
1734
+ b . OwnsOne ( x => x . NestedOptional ) ;
1735
+ b . OwnsOne ( x => x . NestedRequired ) ;
1736
+ b . OwnsMany ( x => x . NestedCollection ) ;
1737
+ } ) ;
1738
+
1739
+ b . OwnsOne (
1740
+ x => x . OptionalReference , b =>
1741
+ {
1742
+ b . ToJson ( ) . HasColumnType ( JsonColumnType ) ;
1743
+ b . OwnsOne ( x => x . NestedOptional ) ;
1744
+ b . OwnsOne ( x => x . NestedRequired ) ;
1745
+ b . OwnsMany ( x => x . NestedCollection ) ;
1746
+ } ) ;
1747
+
1748
+ b . OwnsMany (
1749
+ x => x . Collection , b =>
1750
+ {
1751
+ b . ToJson ( ) . HasColumnType ( JsonColumnType ) ;
1752
+ b . OwnsOne ( x => x . NestedOptional ) ;
1753
+ b . OwnsOne ( x => x . NestedRequired ) ;
1754
+ b . OwnsMany ( x => x . NestedCollection ) ;
1755
+ } ) ;
1756
+ } ) ;
1757
+
1758
+ #endregion
1759
+
1470
1760
protected TestSqlLoggerFactory TestSqlLoggerFactory
1471
1761
=> ( TestSqlLoggerFactory ) ListLoggerFactory ;
1472
1762
0 commit comments