Skip to content

Commit f825529

Browse files
committed
Tests for two recently filed issues
Issue #16483 which is already fixed in 3.0 Issue #16546 which I thought might be fixed, but isn't
1 parent f8ee688 commit f825529

File tree

1 file changed

+264
-0
lines changed

1 file changed

+264
-0
lines changed

test/EFCore.Tests/ChangeTracking/Internal/FixupTest.cs

+264
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Linq;
99
using Microsoft.EntityFrameworkCore.Diagnostics;
1010
using Microsoft.EntityFrameworkCore.Infrastructure;
11+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
1112
using Microsoft.EntityFrameworkCore.Metadata.Internal;
1213
using Microsoft.EntityFrameworkCore.Storage;
1314
using Xunit;
@@ -2753,6 +2754,269 @@ protected internal override void OnConfiguring(DbContextOptionsBuilder optionsBu
27532754
public DbSet<Level2> Level2s { get; set; }
27542755
}
27552756

2757+
[ConditionalFact]
2758+
public void Use_correct_entity_after_SetValues()
2759+
{
2760+
var detachedProduct = new ProductX
2761+
{
2762+
Description = "Heavy Engine XT3"
2763+
};
2764+
2765+
var detachedRoom = new ContainerRoomX
2766+
{
2767+
Number = 1,
2768+
Product = detachedProduct
2769+
};
2770+
2771+
var detachedContainer = new ContainerX
2772+
{
2773+
Name = "C1",
2774+
Rooms =
2775+
{
2776+
detachedRoom
2777+
}
2778+
};
2779+
2780+
using (var context = new EscapeRoom(nameof(EscapeRoom)))
2781+
{
2782+
context.Add(detachedContainer);
2783+
context.SaveChanges();
2784+
}
2785+
2786+
using (var context = new EscapeRoom(nameof(EscapeRoom)))
2787+
{
2788+
var attachedProduct = new ProductX
2789+
{
2790+
Id = detachedProduct.Id,
2791+
Description = "Heavy Engine XT3"
2792+
};
2793+
2794+
var attachedRoom = new ContainerRoomX
2795+
{
2796+
Id = detachedRoom.Id,
2797+
ContainerId = detachedRoom.ContainerId,
2798+
Number = 1,
2799+
ProductId = detachedRoom.ProductId,
2800+
Product = attachedProduct
2801+
};
2802+
2803+
var attached = new ContainerX
2804+
{
2805+
Id = detachedContainer.Id,
2806+
Name = "C1",
2807+
Rooms =
2808+
{
2809+
attachedRoom
2810+
}
2811+
};
2812+
2813+
context.Attach(attached);
2814+
2815+
detachedRoom.Product = null;
2816+
detachedRoom.ProductId = null;
2817+
2818+
context.Entry(attachedRoom).CurrentValues.SetValues(detachedRoom);
2819+
2820+
context.SaveChanges();
2821+
2822+
// Fails - see #16546
2823+
//Assert.Equal(EntityState.Unchanged, context.Entry(attachedRoom).State);
2824+
}
2825+
}
2826+
2827+
public class ContainerX
2828+
{
2829+
public int Id { get; set; }
2830+
public string Name { get; set; }
2831+
public List<ContainerRoomX> Rooms { get; set; } = new List<ContainerRoomX>();
2832+
}
2833+
2834+
public class ContainerRoomX
2835+
{
2836+
public int Id { get; set; }
2837+
public int Number { get; set; }
2838+
public int ContainerId { get; set; }
2839+
public ContainerX Container { get; set; }
2840+
public int? ProductId { get; set; }
2841+
public ProductX Product { get; set; }
2842+
}
2843+
2844+
public class ProductX
2845+
{
2846+
public int Id { get; set; }
2847+
public string Description { get; set; }
2848+
public List<ContainerRoomX> Rooms { get; set; } = new List<ContainerRoomX>();
2849+
}
2850+
2851+
protected class EscapeRoom : DbContext
2852+
{
2853+
private readonly string _databaseName;
2854+
2855+
public EscapeRoom(string databaseName)
2856+
{
2857+
_databaseName = databaseName;
2858+
}
2859+
2860+
protected internal override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
2861+
=> optionsBuilder.UseInMemoryDatabase(_databaseName);
2862+
2863+
protected internal override void OnModelCreating(ModelBuilder modelBuilder)
2864+
{
2865+
modelBuilder.Entity<ContainerRoomX>()
2866+
.HasOne(room => room.Product)
2867+
.WithMany(product => product.Rooms)
2868+
.HasForeignKey(room => room.ProductId)
2869+
.IsRequired(false)
2870+
.OnDelete(DeleteBehavior.Cascade);
2871+
}
2872+
}
2873+
2874+
[ConditionalFact]
2875+
public void Replaced_duplicate_entities_are_used_even_with_bad_hash()
2876+
{
2877+
using (var context = new BadHashDay("BadHashDay"))
2878+
{
2879+
context.AddRange(
2880+
new ParentX
2881+
{
2882+
Id = 101, Name = "Parent1"
2883+
},
2884+
new ChildX
2885+
{
2886+
Id = 201, Name = "Child1"
2887+
},
2888+
new ParentChildX
2889+
{
2890+
ParentId = 101, ChildId = 201, SortOrder = 1
2891+
});
2892+
2893+
context.SaveChanges();
2894+
}
2895+
2896+
using (var context = new BadHashDay("BadHashDay"))
2897+
{
2898+
var parent = context.Set<ParentX>().Single(x => x.Id == 101);
2899+
var join = context.Set<ParentChildX>().Single();
2900+
2901+
Assert.Equal(2, context.ChangeTracker.Entries().Count());
2902+
Assert.Equal(EntityState.Unchanged, context.Entry(parent).State);
2903+
Assert.Equal(EntityState.Unchanged, context.Entry(join).State);
2904+
2905+
parent.ParentChildren.Clear();
2906+
2907+
var newJoin = new ParentChildX
2908+
{
2909+
ParentId = 101,
2910+
ChildId = 201,
2911+
SortOrder = 1
2912+
};
2913+
2914+
parent.ParentChildren = new List<ParentChildX>
2915+
{
2916+
newJoin
2917+
};
2918+
2919+
Assert.Equal(3, context.ChangeTracker.Entries().Count());
2920+
Assert.Equal(EntityState.Unchanged, context.Entry(parent).State);
2921+
Assert.Equal(EntityState.Deleted, context.Entry(join).State);
2922+
Assert.Equal(EntityState.Added, context.Entry(newJoin).State);
2923+
2924+
context.SaveChanges();
2925+
2926+
Assert.Equal(2, context.ChangeTracker.Entries().Count());
2927+
Assert.Equal(EntityState.Unchanged, context.Entry(parent).State);
2928+
Assert.Equal(EntityState.Detached, context.Entry(join).State);
2929+
Assert.Equal(EntityState.Unchanged, context.Entry(newJoin).State);
2930+
}
2931+
}
2932+
2933+
protected class ParentX
2934+
{
2935+
public int Id { get; set; }
2936+
public string Name { get; set; }
2937+
public virtual IList<ParentChildX> ParentChildren { get; set; } = new List<ParentChildX>();
2938+
}
2939+
2940+
protected class ParentChildX
2941+
{
2942+
public int ParentId { get; set; }
2943+
public int ChildId { get; set; }
2944+
public int SortOrder { get; set; }
2945+
public virtual ParentX Parent { get; set; }
2946+
public virtual ChildX Child { get; set; }
2947+
2948+
// Bad implementation of Equals to test for regression
2949+
public override bool Equals(object obj)
2950+
{
2951+
if (obj == null)
2952+
{
2953+
return false;
2954+
}
2955+
2956+
var other = (ParentChildX)obj;
2957+
2958+
if (!Equals(ParentId, other.ParentId))
2959+
{
2960+
return false;
2961+
}
2962+
2963+
if (!Equals(ChildId, other.ChildId))
2964+
{
2965+
return false;
2966+
}
2967+
2968+
return true;
2969+
}
2970+
2971+
// Bad implementation of GetHashCode to test for regression
2972+
public override int GetHashCode()
2973+
{
2974+
var hashCode = 13;
2975+
hashCode = (hashCode * 7) + ParentId.GetHashCode();
2976+
hashCode = (hashCode * 7) + ChildId.GetHashCode();
2977+
return hashCode;
2978+
}
2979+
}
2980+
2981+
protected class ChildX
2982+
{
2983+
public int Id { get; set; }
2984+
public string Name { get; set; }
2985+
public virtual IList<ParentChildX> ParentChildren { get; set; } = new List<ParentChildX>();
2986+
}
2987+
2988+
protected class BadHashDay : DbContext
2989+
{
2990+
private readonly string _databaseName;
2991+
2992+
public BadHashDay(string databaseName)
2993+
{
2994+
_databaseName = databaseName;
2995+
}
2996+
2997+
protected internal override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
2998+
=> optionsBuilder.UseInMemoryDatabase(_databaseName);
2999+
3000+
protected internal override void OnModelCreating(ModelBuilder modelBuilder)
3001+
{
3002+
modelBuilder.Entity<ParentX>()
3003+
.HasMany(x => x.ParentChildren)
3004+
.WithOne(op => op.Parent)
3005+
.IsRequired();
3006+
3007+
modelBuilder.Entity<ChildX>()
3008+
.HasMany(x => x.ParentChildren)
3009+
.WithOne(op => op.Child)
3010+
.IsRequired();
3011+
3012+
modelBuilder.Entity<ParentChildX>().HasKey(
3013+
x => new
3014+
{
3015+
x.ParentId, x.ChildId
3016+
});
3017+
}
3018+
}
3019+
27563020
[ConditionalFact]
27573021
public void Detached_entity_is_not_replaced_by_tracked_entity()
27583022
{

0 commit comments

Comments
 (0)