You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
EntityFrameworkCore.Jet/test/EFCore.Jet.FunctionalTests/GraphUpdates/GraphUpdatesJetOwnedTest.cs

635 lines
26 KiB
C#

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
using System.Threading.Tasks;
namespace EntityFrameworkCore.Jet.FunctionalTests;
#nullable disable
public class GraphUpdatesJetOwnedTest(GraphUpdatesJetOwnedTest.JetFixture fixture)
: GraphUpdatesJetTestBase<GraphUpdatesJetOwnedTest.JetFixture>(fixture)
{
// No owned types
public override Task Update_root_by_collection_replacement_of_inserted_first_level(bool async)
=> Task.CompletedTask;
// No owned types
public override Task Mark_explicitly_set_dependent_appropriately_with_any_inheritance_and_stable_generator(bool async, bool useAdd)
=> Task.CompletedTask;
// No owned types
public override Task Mark_explicitly_set_stable_dependent_appropriately(bool async, bool useAdd)
=> Task.CompletedTask;
// No owned types
public override Task Mark_explicitly_set_stable_dependent_appropriately_when_deep_in_graph(bool async, bool useAdd)
=> Task.CompletedTask;
// No owned types
public override Task Update_root_by_collection_replacement_of_deleted_first_level(bool async)
=> Task.CompletedTask;
// No owned types
public override Task Update_root_by_collection_replacement_of_inserted_second_level(bool async)
=> Task.CompletedTask;
// No owned types
public override Task Update_root_by_collection_replacement_of_deleted_second_level(bool async)
=> Task.CompletedTask;
// No owned types
public override Task Update_root_by_collection_replacement_of_inserted_first_level_level(bool async)
=> Task.CompletedTask;
// No owned types
public override Task Update_root_by_collection_replacement_of_deleted_third_level(bool async)
=> Task.CompletedTask;
// No owned types
public override Task Sever_relationship_that_will_later_be_deleted(bool async)
=> Task.CompletedTask;
// No owned types
public override Task Alternate_key_over_foreign_key_doesnt_bypass_delete_behavior(bool async)
=> Task.CompletedTask;
// No owned types
public override Task Shadow_skip_navigation_in_base_class_is_handled(bool async)
=> Task.CompletedTask;
// Owned dependents are always loaded
public override Task Required_one_to_one_are_cascade_deleted_in_store(
CascadeTiming? cascadeDeleteTiming,
CascadeTiming? deleteOrphansTiming)
=> Task.CompletedTask;
public override Task Required_one_to_one_with_alternate_key_are_cascade_deleted_in_store(
CascadeTiming? cascadeDeleteTiming,
CascadeTiming? deleteOrphansTiming)
=> Task.CompletedTask;
// No owned types
public override Task Can_insert_when_composite_FK_has_default_value_for_one_part(bool async)
=> Task.CompletedTask;
public override Task Required_one_to_one_relationships_are_one_to_one(CascadeTiming? deleteOrphansTiming)
=> Task.CompletedTask;
public override Task Required_one_to_one_with_AK_relationships_are_one_to_one(CascadeTiming? deleteOrphansTiming)
=> Task.CompletedTask;
// No owned types
public override Task Can_insert_when_bool_PK_in_composite_key_has_sentinel_value(bool async, bool initialValue)
=> Task.CompletedTask;
// No owned types
public override Task Can_insert_when_int_PK_in_composite_key_has_sentinel_value(bool async, int initialValue)
=> Task.CompletedTask;
// No owned types
public override Task Can_insert_when_nullable_bool_PK_in_composite_key_has_sentinel_value(bool async, bool? initialValue)
=> Task.CompletedTask;
// No owned types
public override Task Throws_for_single_property_bool_key_with_default_value_generation(bool async, bool initialValue)
=> Task.CompletedTask;
// No owned types
public override Task Throws_for_single_property_nullable_bool_key_with_default_value_generation(bool async, bool? initialValue)
=> Task.CompletedTask;
protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
=> facade.UseTransaction(transaction.GetDbTransaction());
public class JetFixture : GraphUpdatesJetFixtureBase
{
protected override string StoreName
=> "GraphOwnedUpdatesTest";
protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context)
{
modelBuilder.Entity<OwnerRoot>(
b =>
{
b.OwnsOne(e => e.OptionalSingle).OwnsOne(e => e.Single);
b.OwnsOne(e => e.RequiredSingle).OwnsOne(e => e.Single);
b.OwnsMany(e => e.OptionalChildren).OwnsMany(e => e.Children);
b.OwnsMany(e => e.RequiredChildren).OwnsMany(e => e.Children);
});
modelBuilder.Entity<Root>(
b =>
{
b.Property(e => e.AlternateId).ValueGeneratedOnAdd();
// TODO: Owned inheritance support #9630
b.HasMany(e => e.RequiredChildren)
.WithOne(e => e.Parent)
.HasForeignKey(e => e.ParentId);
modelBuilder.Entity<Required1>()
.HasMany(e => e.Children)
.WithOne(e => e.Parent)
.HasForeignKey(e => e.ParentId);
modelBuilder.Entity<Required1Derived>();
modelBuilder.Entity<Required1MoreDerived>();
modelBuilder.Entity<Required2Derived>();
modelBuilder.Entity<Required2MoreDerived>();
b.HasMany(e => e.OptionalChildren)
.WithOne(e => e.Parent)
.HasForeignKey(e => e.ParentId)
.OnDelete(DeleteBehavior.SetNull);
b.OwnsOne(
e => e.RequiredSingle, r =>
{
r.WithOwner(e => e.Root)
.HasForeignKey(e => e.Id);
r.OwnsOne(e => e.Single)
.WithOwner(e => e.Back)
.HasForeignKey(e => e.Id);
});
b.HasOne(e => e.OptionalSingle)
.WithOne(e => e.Root)
.HasForeignKey<OptionalSingle1>(e => e.RootId)
.OnDelete(DeleteBehavior.SetNull);
b.HasOne(e => e.OptionalSingleDerived)
.WithOne(e => e.DerivedRoot)
.HasForeignKey<OptionalSingle1Derived>(e => e.DerivedRootId)
.OnDelete(DeleteBehavior.ClientSetNull);
b.HasOne(e => e.OptionalSingleMoreDerived)
.WithOne(e => e.MoreDerivedRoot)
.HasForeignKey<OptionalSingle1MoreDerived>(e => e.MoreDerivedRootId)
.OnDelete(DeleteBehavior.ClientSetNull);
// TODO: Owned inheritance support #9630
b.HasOne(e => e.RequiredNonPkSingle)
.WithOne(e => e.Root)
.HasForeignKey<RequiredNonPkSingle1>(e => e.RootId);
b.HasOne(e => e.RequiredNonPkSingleDerived)
.WithOne(e => e.DerivedRoot)
.HasForeignKey<RequiredNonPkSingle1Derived>(e => e.DerivedRootId)
.OnDelete(DeleteBehavior.Restrict);
b.HasOne(e => e.RequiredNonPkSingleMoreDerived)
.WithOne(e => e.MoreDerivedRoot)
.HasForeignKey<RequiredNonPkSingle1MoreDerived>(e => e.MoreDerivedRootId)
.OnDelete(DeleteBehavior.Restrict);
// TODO: Owned inheritance support #9630
b.HasMany(e => e.RequiredChildrenAk)
.WithOne(e => e.Parent)
.HasPrincipalKey(e => e.AlternateId)
.HasForeignKey(e => e.ParentId);
modelBuilder.Entity<RequiredAk1>(
b =>
{
b.Property(e => e.AlternateId)
.ValueGeneratedOnAdd();
b.HasMany(e => e.Children)
.WithOne(e => e.Parent)
.HasPrincipalKey(e => e.AlternateId)
.HasForeignKey(e => e.ParentId);
b.HasMany(e => e.CompositeChildren)
.WithOne(e => e.Parent)
.HasPrincipalKey(
e => new { e.Id, e.AlternateId })
.HasForeignKey(
e => new { e.ParentId, e.ParentAlternateId });
});
modelBuilder.Entity<RequiredAk2>()
.Property(e => e.AlternateId)
.ValueGeneratedOnAdd();
modelBuilder.Entity<RequiredAk2Derived>();
modelBuilder.Entity<RequiredAk2MoreDerived>();
modelBuilder.Entity<RequiredAk1Derived>();
modelBuilder.Entity<RequiredAk1MoreDerived>();
b.HasMany(e => e.OptionalChildrenAk)
.WithOne(e => e.Parent)
.HasPrincipalKey(e => e.AlternateId)
.HasForeignKey(e => e.ParentId)
.OnDelete(DeleteBehavior.SetNull);
b.OwnsOne(
e => e.RequiredSingleAk, r =>
{
r.WithOwner(e => e.Root)
.HasPrincipalKey(e => e.AlternateId)
.HasForeignKey(e => e.RootId);
r.HasKey(e => e.Id);
r.Property(e => e.AlternateId)
.ValueGeneratedOnAdd();
r.OwnsOne(
e => e.Single, r2 =>
{
r2.WithOwner(e => e.Back)
.HasForeignKey(e => e.BackId)
.HasPrincipalKey(e => e.AlternateId);
r2.HasKey(e => e.Id);
r2.Property(e => e.Id)
.ValueGeneratedOnAdd();
r2.Property(e => e.AlternateId)
.ValueGeneratedOnAdd();
r2.ToTable("RequiredSingleAk2");
});
r.OwnsOne(
e => e.SingleComposite, r2 =>
{
r2.WithOwner(e => e.Back)
.HasForeignKey(e => new { e.BackId, e.BackAlternateId })
.HasPrincipalKey(e => new { e.Id, e.AlternateId });
r2.HasKey(e => e.Id);
r2.ToTable("RequiredSingleComposite2");
});
// Table splitting using AK is not supported #23208
r.ToTable("RequiredSingleAk1");
});
b.HasOne(e => e.OptionalSingleAk)
.WithOne(e => e.Root)
.HasPrincipalKey<Root>(e => e.AlternateId)
.HasForeignKey<OptionalSingleAk1>(e => e.RootId)
.OnDelete(DeleteBehavior.SetNull);
b.HasOne(e => e.OptionalSingleAkDerived)
.WithOne(e => e.DerivedRoot)
.HasPrincipalKey<Root>(e => e.AlternateId)
.HasForeignKey<OptionalSingleAk1Derived>(e => e.DerivedRootId)
.OnDelete(DeleteBehavior.ClientSetNull);
b.HasOne(e => e.OptionalSingleAkMoreDerived)
.WithOne(e => e.MoreDerivedRoot)
.HasPrincipalKey<Root>(e => e.AlternateId)
.HasForeignKey<OptionalSingleAk1MoreDerived>(e => e.MoreDerivedRootId)
.OnDelete(DeleteBehavior.ClientSetNull);
b.HasOne(e => e.RequiredNonPkSingleAk)
.WithOne(e => e.Root)
.HasPrincipalKey<Root>(e => e.AlternateId)
.HasForeignKey<RequiredNonPkSingleAk1>(e => e.RootId);
b.HasOne(e => e.RequiredNonPkSingleAkDerived)
.WithOne(e => e.DerivedRoot)
.HasPrincipalKey<Root>(e => e.AlternateId)
.HasForeignKey<RequiredNonPkSingleAk1Derived>(e => e.DerivedRootId)
.OnDelete(DeleteBehavior.Restrict);
b.HasOne(e => e.RequiredNonPkSingleAkMoreDerived)
.WithOne(e => e.MoreDerivedRoot)
.HasPrincipalKey<Root>(e => e.AlternateId)
.HasForeignKey<RequiredNonPkSingleAk1MoreDerived>(e => e.MoreDerivedRootId)
.OnDelete(DeleteBehavior.Restrict);
b.HasMany(e => e.RequiredCompositeChildren)
.WithOne(e => e.Parent)
.HasPrincipalKey(e => e.AlternateId)
.HasForeignKey(e => e.ParentAlternateId);
});
modelBuilder.Entity<Optional1>(
b =>
{
b.HasMany(e => e.Children)
.WithOne(e => e.Parent)
.HasForeignKey(e => e.ParentId)
.OnDelete(DeleteBehavior.SetNull);
b.HasMany(e => e.CompositeChildren)
.WithOne(e => e.Parent2)
.HasForeignKey(e => new { e.Parent2Id });
});
modelBuilder.Entity<Optional1Derived>();
modelBuilder.Entity<Optional1MoreDerived>();
modelBuilder.Entity<Optional2Derived>();
modelBuilder.Entity<Optional2MoreDerived>();
modelBuilder.Entity<OptionalSingle1>()
.HasOne(e => e.Single)
.WithOne(e => e.Back)
.HasForeignKey<OptionalSingle2>(e => e.BackId)
.OnDelete(DeleteBehavior.SetNull);
modelBuilder.Entity<OptionalSingle2>(
b =>
{
b.HasDiscriminator(e => e.Disc)
.HasValue<OptionalSingle2>(new MyDiscriminator(1))
.HasValue<OptionalSingle2Derived>(new MyDiscriminator(2))
.HasValue<OptionalSingle2MoreDerived>(new MyDiscriminator(3));
b.Property(e => e.Disc)
.HasConversion(
v => v.Value,
v => new MyDiscriminator(v),
new ValueComparer<MyDiscriminator>(
(l, r) => l.Value == r.Value,
v => v.Value.GetHashCode(),
v => new MyDiscriminator(v.Value)))
.Metadata
.SetAfterSaveBehavior(PropertySaveBehavior.Save);
});
modelBuilder.Entity<RequiredNonPkSingle1>()
.HasOne(e => e.Single)
.WithOne(e => e.Back)
.HasForeignKey<RequiredNonPkSingle2>(e => e.BackId);
modelBuilder.Entity<RequiredNonPkSingle2Derived>();
modelBuilder.Entity<RequiredNonPkSingle2MoreDerived>();
modelBuilder.Entity<RequiredNonPkSingleAk1>(
b =>
{
b.Property(e => e.AlternateId)
.ValueGeneratedOnAdd();
b.HasOne(e => e.Single)
.WithOne(e => e.Back)
.HasForeignKey<RequiredNonPkSingleAk2>(e => e.BackId)
.HasPrincipalKey<RequiredNonPkSingleAk1>(e => e.AlternateId);
});
modelBuilder.Entity<OptionalAk1>(
b =>
{
b.Property(e => e.AlternateId)
.ValueGeneratedOnAdd();
b.HasMany(e => e.Children)
.WithOne(e => e.Parent)
.HasPrincipalKey(e => e.AlternateId)
.HasForeignKey(e => e.ParentId)
.OnDelete(DeleteBehavior.SetNull);
b.HasMany(e => e.CompositeChildren)
.WithOne(e => e.Parent)
.HasPrincipalKey(
e => new { e.Id, e.AlternateId })
.HasForeignKey(
e => new { e.ParentId, e.ParentAlternateId });
});
modelBuilder.Entity<OptionalAk1Derived>();
modelBuilder.Entity<OptionalAk1MoreDerived>();
modelBuilder.Entity<OptionalAk2>()
.Property(e => e.AlternateId)
.ValueGeneratedOnAdd();
modelBuilder.Entity<OptionalAk2Derived>();
modelBuilder.Entity<OptionalAk2MoreDerived>();
modelBuilder.Entity<RequiredNonPkSingleAk2>()
.Property(e => e.AlternateId)
.ValueGeneratedOnAdd();
modelBuilder.Entity<RequiredNonPkSingleAk2Derived>();
modelBuilder.Entity<RequiredNonPkSingleAk2MoreDerived>();
modelBuilder.Entity<OptionalSingleAk1>(
b =>
{
b.Property(e => e.AlternateId)
.ValueGeneratedOnAdd();
b.HasOne(e => e.Single)
.WithOne(e => e.Back)
.HasForeignKey<OptionalSingleAk2>(e => e.BackId)
.HasPrincipalKey<OptionalSingleAk1>(e => e.AlternateId)
.OnDelete(DeleteBehavior.SetNull);
b.HasOne(e => e.SingleComposite)
.WithOne(e => e.Back)
.HasForeignKey<OptionalSingleComposite2>(
e => new { e.BackId, e.ParentAlternateId })
.HasPrincipalKey<OptionalSingleAk1>(
e => new { e.Id, e.AlternateId });
});
modelBuilder.Entity<OptionalSingleAk2>()
.Property(e => e.AlternateId)
.ValueGeneratedOnAdd();
modelBuilder.Entity<OptionalSingleAk2Derived>();
modelBuilder.Entity<OptionalSingleAk2MoreDerived>();
modelBuilder.Entity<RequiredComposite1>(
eb =>
{
eb.Property(e => e.Id).ValueGeneratedNever();
eb.HasKey(
e => new { e.Id, e.ParentAlternateId });
eb.HasMany(e => e.CompositeChildren)
.WithOne(e => e.Parent)
.HasPrincipalKey(
e => new { e.Id, e.ParentAlternateId })
.HasForeignKey(
e => new { e.ParentId, e.ParentAlternateId });
});
modelBuilder.Entity<OptionalOverlapping2>(
eb =>
{
eb.Property(e => e.Id).ValueGeneratedNever();
eb.HasKey(
e => new { e.Id, e.ParentAlternateId });
eb.HasOne(e => e.Root)
.WithMany()
.HasPrincipalKey(e => e.AlternateId)
.HasForeignKey(e => e.ParentAlternateId);
});
modelBuilder.Entity<BadCustomer>();
modelBuilder.Entity<BadOrder>();
modelBuilder.Entity<QuestTask>();
modelBuilder.Entity<QuizTask>()
.HasMany(qt => qt.Choices)
.WithOne()
.HasForeignKey(tc => tc.QuestTaskId);
modelBuilder.Entity<HiddenAreaTask>()
.HasMany(hat => hat.Choices)
.WithOne()
.HasForeignKey(tc => tc.QuestTaskId);
modelBuilder.Entity<TaskChoice>();
modelBuilder.Entity<ParentAsAChild>();
modelBuilder.Entity<ChildAsAParent>();
modelBuilder.Entity<Poost>();
modelBuilder.Entity<Bloog>();
modelBuilder.Entity<Produce>()
.HasIndex(e => e.BarCode)
.IsUnique();
modelBuilder.Entity<SharedFkRoot>(
builder =>
{
builder.HasMany(x => x.Dependants).WithOne(x => x.Root)
.HasForeignKey(x => new { x.RootId })
.HasPrincipalKey(x => x.Id)
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(x => x.Parents).WithOne(x => x.Root)
.HasForeignKey(x => new { x.RootId })
.HasPrincipalKey(x => x.Id)
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<SharedFkParent>(
builder =>
{
builder.HasOne(x => x.Dependant).WithOne(x => x!.Parent).IsRequired(false)
.HasForeignKey<SharedFkParent>(x => new { x.RootId, x.DependantId })
.HasPrincipalKey<SharedFkDependant>(x => new { x.RootId, x.Id })
.OnDelete(DeleteBehavior.ClientSetNull);
});
modelBuilder.Entity<SharedFkDependant>();
modelBuilder.Entity<Owner>();
modelBuilder.Entity<OwnerWithKeyedCollection>(
b =>
{
b.Navigation(e => e.Owned).IsRequired();
b.Navigation(e => e.OwnedWithKey).IsRequired();
b.OwnsMany(
e => e.OwnedCollectionPrivateKey,
b => b.HasKey("OwnerWithKeyedCollectionId", "PrivateKey"));
});
modelBuilder
.Entity<OwnerWithNonCompositeOwnedCollection>()
.OwnsMany(e => e.Owned, owned => owned.HasKey("Id"));
modelBuilder.Entity<OwnerNoKeyGeneration>(
b =>
{
b.Property(e => e.Id).ValueGeneratedNever();
b.OwnsOne(
e => e.Owned,
b => b.Property("OwnerNoKeyGenerationId").ValueGeneratedNever());
b.OwnsMany(
e => e.OwnedCollection,
b =>
{
b.Property<int>("OwnedNoKeyGenerationId").ValueGeneratedNever();
b.Property("OwnerNoKeyGenerationId").ValueGeneratedNever();
});
});
modelBuilder.Entity<Provider>().HasData(
new Provider { Id = "prov1" },
new Provider { Id = "prov2" });
modelBuilder.Entity<Partner>().HasData(
new Partner { Id = "partner1" });
modelBuilder.Entity<ProviderContract>(
b =>
{
b.HasOne(p => p.Partner).WithMany().IsRequired().HasForeignKey("PartnerId");
b.HasOne<Provider>().WithMany().IsRequired().HasForeignKey("ProviderId");
b.HasDiscriminator<string>("ProviderId")
.HasValue<ProviderContract1>("prov1")
.HasValue<ProviderContract2>("prov2");
});
modelBuilder.Entity<EventDescriptorZ>(
b =>
{
b.Property<long>("EntityZId");
b.HasOne(e => e.EntityZ).WithMany().HasForeignKey("EntityZId").IsRequired();
});
modelBuilder.Entity<City>();
modelBuilder.Entity<AccessState>(
b =>
{
b.Property(e => e.AccessStateId).ValueGeneratedNever();
b.HasData(new AccessState { AccessStateId = 1 });
});
modelBuilder.Entity<Cruiser>(
b =>
{
b.Property(e => e.IdUserState).HasDefaultValue(1);
b.HasOne(e => e.UserState).WithMany(e => e.Users).HasForeignKey(e => e.IdUserState);
});
modelBuilder.Entity<AccessStateWithSentinel>(
b =>
{
b.Property(e => e.AccessStateWithSentinelId).ValueGeneratedNever();
b.HasData(new AccessStateWithSentinel { AccessStateWithSentinelId = 1 });
});
modelBuilder.Entity<CruiserWithSentinel>(
b =>
{
b.Property(e => e.IdUserState).HasDefaultValue(1).HasSentinel(667);
b.HasOne(e => e.UserState).WithMany(e => e.Users).HasForeignKey(e => e.IdUserState);
});
modelBuilder.Entity<StringKeyAndIndexParent>(
b =>
{
b.HasAlternateKey(e => e.AlternateId);
b.OwnsOne(
x => x.Child, b =>
{
b.WithOwner(e => e.Parent).HasForeignKey(e => e.ParentId);
});
});
modelBuilder.Entity<SharedFkRoot>().Property(x => x.Id).HasColumnType("int");
modelBuilder.Entity<SharedFkDependant>().Property(x => x.Id).HasColumnType("int");
modelBuilder.Entity<SharedFkParent>().Property(x => x.Id).HasColumnType("int");
}
}
}