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.
1771 lines
84 KiB
C#
1771 lines
84 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 System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.ComponentModel.DataAnnotations.Schema;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
using Microsoft.EntityFrameworkCore.Metadata;
|
|
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
|
|
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
|
|
using Microsoft.EntityFrameworkCore.ModelBuilding;
|
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
using Microsoft.EntityFrameworkCore.TestUtilities;
|
|
using Xunit;
|
|
using System.Linq;
|
|
using EntityFrameworkCore.Jet.FunctionalTests.TestUtilities;
|
|
|
|
namespace EntityFrameworkCore.Jet.FunctionalTests.ModelBuilding;
|
|
|
|
public class JetModelBuilderTestBase : RelationalModelBuilderTest
|
|
{
|
|
public abstract class JetNonRelationship(JetModelBuilderFixture fixture) : RelationalNonRelationshipTestBase(fixture), IClassFixture<JetModelBuilderFixture>
|
|
{
|
|
[ConditionalFact]
|
|
public virtual void Index_has_a_filter_if_nonclustered_unique_with_nullable_properties()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
var entityTypeBuilder = modelBuilder
|
|
.Entity<Customer>();
|
|
var indexBuilder = entityTypeBuilder
|
|
.HasIndex(ix => ix.Name)
|
|
.IsUnique();
|
|
|
|
var entityType = modelBuilder.Model.FindEntityType(typeof(Customer))!;
|
|
var index = entityType.GetIndexes().Single();
|
|
Assert.Equal("[Name] IS NOT NULL", index.GetFilter());
|
|
|
|
indexBuilder.IsUnique(false);
|
|
|
|
Assert.Null(index.GetFilter());
|
|
|
|
indexBuilder.IsUnique();
|
|
|
|
Assert.Equal("[Name] IS NOT NULL", index.GetFilter());
|
|
|
|
/*indexBuilder.IsClustered();
|
|
|
|
Assert.Null(index.GetFilter());
|
|
|
|
indexBuilder.IsClustered(false);*/
|
|
|
|
Assert.Equal("[Name] IS NOT NULL", index.GetFilter());
|
|
|
|
entityTypeBuilder.Property(e => e.Name).IsRequired();
|
|
|
|
Assert.Null(index.GetFilter());
|
|
|
|
entityTypeBuilder.Property(e => e.Name).IsRequired(false);
|
|
|
|
Assert.Equal("[Name] IS NOT NULL", index.GetFilter());
|
|
|
|
entityTypeBuilder.Property(e => e.Name).HasColumnName("RelationalName");
|
|
|
|
Assert.Equal("[RelationalName] IS NOT NULL", index.GetFilter());
|
|
|
|
entityTypeBuilder.Property(e => e.Name).HasColumnName("SqlServerName");
|
|
|
|
Assert.Equal("[SqlServerName] IS NOT NULL", index.GetFilter());
|
|
|
|
entityTypeBuilder.Property(e => e.Name).HasColumnName(null);
|
|
|
|
Assert.Equal("[Name] IS NOT NULL", index.GetFilter());
|
|
|
|
indexBuilder.HasFilter("Foo");
|
|
|
|
Assert.Equal("Foo", index.GetFilter());
|
|
|
|
indexBuilder.HasFilter(null);
|
|
|
|
Assert.Null(index.GetFilter());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public void Indexes_can_have_same_name_across_tables()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<Customer>()
|
|
.HasIndex(e => e.Id, "Ix_Id")
|
|
.IsUnique();
|
|
modelBuilder.Entity<CustomerDetails>()
|
|
.HasIndex(e => e.CustomerId, "Ix_Id")
|
|
.IsUnique();
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var customerIndex = model.FindEntityType(typeof(Customer))!.GetIndexes().Single();
|
|
Assert.Equal("Ix_Id", customerIndex.Name);
|
|
Assert.Equal("Ix_Id", customerIndex.GetDatabaseName());
|
|
Assert.Equal(
|
|
"Ix_Id", customerIndex.GetDatabaseName(
|
|
StoreObjectIdentifier.Table("Customer")));
|
|
|
|
var detailsIndex = model.FindEntityType(typeof(CustomerDetails))!.GetIndexes().Single();
|
|
Assert.Equal("Ix_Id", detailsIndex.Name);
|
|
Assert.Equal("Ix_Id", detailsIndex.GetDatabaseName());
|
|
Assert.Equal(
|
|
"Ix_Id", detailsIndex.GetDatabaseName(
|
|
StoreObjectIdentifier.Table("CustomerDetails")));
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Can_set_store_type_for_property_type()
|
|
{
|
|
var modelBuilder = CreateModelBuilder(
|
|
c =>
|
|
{
|
|
c.Properties<int>().HaveColumnType("smallint");
|
|
c.Properties<string>().HaveColumnType("nchar(max)");
|
|
c.Properties(typeof(Nullable<>)).HavePrecision(2);
|
|
});
|
|
|
|
modelBuilder.Entity<Quarks>(
|
|
b =>
|
|
{
|
|
b.Property<int>("Charm");
|
|
b.Property<string>("Strange");
|
|
b.Property<int?>("Top");
|
|
b.Property<string>("Bottom");
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var entityType = model.FindEntityType(typeof(Quarks))!;
|
|
|
|
Assert.Equal("smallint", entityType.FindProperty(Customer.IdProperty.Name)!.GetColumnType());
|
|
Assert.Equal("smallint", entityType.FindProperty("Up")!.GetColumnType());
|
|
Assert.Equal("nchar(max)", entityType.FindProperty("Down")!.GetColumnType());
|
|
var charm = entityType.FindProperty("Charm")!;
|
|
Assert.Equal("smallint", charm.GetColumnType());
|
|
Assert.Null(charm.GetPrecision());
|
|
Assert.Equal("nchar(max)", entityType.FindProperty("Strange")!.GetColumnType());
|
|
var top = entityType.FindProperty("Top")!;
|
|
Assert.Equal("smallint", top.GetColumnType());
|
|
Assert.Equal(2, top.GetPrecision());
|
|
Assert.Equal("nchar(max)", entityType.FindProperty("Bottom")!.GetColumnType());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Can_set_fixed_length_for_property_type()
|
|
{
|
|
var modelBuilder = CreateModelBuilder(
|
|
c =>
|
|
{
|
|
c.Properties<int>().AreFixedLength(false);
|
|
c.Properties<string>().AreFixedLength();
|
|
});
|
|
|
|
modelBuilder.Entity<Quarks>(
|
|
b =>
|
|
{
|
|
b.Property<int>("Charm");
|
|
b.Property<string>("Strange");
|
|
b.Property<int>("Top");
|
|
b.Property<string>("Bottom");
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var entityType = model.FindEntityType(typeof(Quarks))!;
|
|
|
|
Assert.False(entityType.FindProperty(Customer.IdProperty.Name)!.IsFixedLength());
|
|
Assert.False(entityType.FindProperty("Up")!.IsFixedLength());
|
|
Assert.True(entityType.FindProperty("Down")!.IsFixedLength());
|
|
Assert.False(entityType.FindProperty("Charm")!.IsFixedLength());
|
|
Assert.True(entityType.FindProperty("Strange")!.IsFixedLength());
|
|
Assert.False(entityType.FindProperty("Top")!.IsFixedLength());
|
|
Assert.True(entityType.FindProperty("Bottom")!.IsFixedLength());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Can_set_collation_for_property_type()
|
|
{
|
|
var modelBuilder = CreateModelBuilder(
|
|
c =>
|
|
{
|
|
c.Properties<int>().UseCollation("Latin1_General_CS_AS_KS_WS");
|
|
c.Properties<string>().UseCollation("Latin1_General_BIN");
|
|
});
|
|
|
|
modelBuilder.Entity<Quarks>(
|
|
b =>
|
|
{
|
|
b.Property<int>("Charm");
|
|
b.Property<string>("Strange");
|
|
b.Property<int>("Top");
|
|
b.Property<string>("Bottom");
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var entityType = model.FindEntityType(typeof(Quarks))!;
|
|
|
|
Assert.Equal("Latin1_General_CS_AS_KS_WS", entityType.FindProperty(Customer.IdProperty.Name)!.GetCollation());
|
|
Assert.Equal("Latin1_General_CS_AS_KS_WS", entityType.FindProperty("Up")!.GetCollation());
|
|
Assert.Equal("Latin1_General_BIN", entityType.FindProperty("Down")!.GetCollation());
|
|
Assert.Equal("Latin1_General_CS_AS_KS_WS", entityType.FindProperty("Charm")!.GetCollation());
|
|
Assert.Equal("Latin1_General_BIN", entityType.FindProperty("Strange")!.GetCollation());
|
|
Assert.Equal("Latin1_General_CS_AS_KS_WS", entityType.FindProperty("Top")!.GetCollation());
|
|
Assert.Equal("Latin1_General_BIN", entityType.FindProperty("Bottom")!.GetCollation());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Can_set_store_type_for_primitive_collection()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<CollectionQuarks>(
|
|
b =>
|
|
{
|
|
b.PrimitiveCollection(e => e.Up).HasColumnType("national character varying(255)");
|
|
b.PrimitiveCollection(e => e.Down).HasColumnType("nchar(10)");
|
|
b.PrimitiveCollection<int[]>("Charm").HasColumnType("nvarchar(25)");
|
|
b.PrimitiveCollection<string[]>("Strange").HasColumnType("text");
|
|
b.PrimitiveCollection<ObservableCollection<int>>("Top").HasColumnType("char(100)");
|
|
;
|
|
b.PrimitiveCollection<ObservableCollection<string>?>("Bottom").HasColumnType("varchar(max)");
|
|
;
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var entityType = model.FindEntityType(typeof(CollectionQuarks))!;
|
|
|
|
Assert.Equal("integer", entityType.FindProperty(nameof(CollectionQuarks.Id))!.GetColumnType());
|
|
Assert.Equal("national character varying(255)", entityType.FindProperty("Up")!.GetColumnType());
|
|
Assert.Equal("nchar(10)", entityType.FindProperty("Down")!.GetColumnType());
|
|
Assert.Equal("nvarchar(25)", entityType.FindProperty("Charm")!.GetColumnType());
|
|
Assert.Equal("text", entityType.FindProperty("Strange")!.GetColumnType());
|
|
Assert.Equal("char(100)", entityType.FindProperty("Top")!.GetColumnType());
|
|
Assert.Equal("varchar(max)", entityType.FindProperty("Bottom")!.GetColumnType());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Can_set_fixed_length_for_primitive_collection()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<CollectionQuarks>(
|
|
b =>
|
|
{
|
|
b.PrimitiveCollection(e => e.Up).IsFixedLength(false);
|
|
b.PrimitiveCollection(e => e.Down).IsFixedLength();
|
|
b.PrimitiveCollection<int[]>("Charm").IsFixedLength();
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var entityType = model.FindEntityType(typeof(CollectionQuarks))!;
|
|
|
|
Assert.False(entityType.FindProperty("Up")!.IsFixedLength());
|
|
Assert.True(entityType.FindProperty("Down")!.IsFixedLength());
|
|
Assert.True(entityType.FindProperty("Charm")!.IsFixedLength());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Can_set_collation_for_primitive_collection()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<CollectionQuarks>(
|
|
b =>
|
|
{
|
|
b.PrimitiveCollection(e => e.Up).UseCollation("Latin1_General_CS_AS_KS_WS");
|
|
b.PrimitiveCollection(e => e.Down).UseCollation("Latin1_General_BIN");
|
|
b.PrimitiveCollection<int[]>("Charm").UseCollation("Latin1_General_CI_AI");
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var entityType = model.FindEntityType(typeof(CollectionQuarks))!;
|
|
|
|
Assert.Equal("Latin1_General_CS_AS_KS_WS", entityType.FindProperty("Up")!.GetCollation());
|
|
Assert.Equal("Latin1_General_BIN", entityType.FindProperty("Down")!.GetCollation());
|
|
Assert.Equal("Latin1_General_CI_AI", entityType.FindProperty("Charm")!.GetCollation());
|
|
}
|
|
|
|
/*[ConditionalTheory]
|
|
[InlineData(true)]
|
|
[InlineData(false)]
|
|
public virtual void Can_avoid_attributes_when_discovering_properties(bool useAttributes)
|
|
{
|
|
var modelBuilder = CreateModelBuilder(c => c.Conventions.Replace(
|
|
s => new PropertyDiscoveryConvention(
|
|
s.GetService<ProviderConventionSetBuilderDependencies>()!, useAttributes)));
|
|
modelBuilder.Entity<SqlVariantEntity>();
|
|
|
|
if (useAttributes)
|
|
{
|
|
var model = modelBuilder.FinalizeModel();
|
|
var entityType = model.FindEntityType(typeof(SqlVariantEntity))!;
|
|
|
|
Assert.Equal([nameof(SqlVariantEntity.Id), nameof(SqlVariantEntity.Value),],
|
|
entityType.GetProperties().Select(p => p.Name));
|
|
}
|
|
else
|
|
{
|
|
Assert.Equal(CoreStrings.PropertyNotAdded(nameof(SqlVariantEntity), nameof(SqlVariantEntity.Value), "object"),
|
|
Assert.Throws<InvalidOperationException>(modelBuilder.FinalizeModel).Message);
|
|
}
|
|
}*/
|
|
|
|
protected class SqlVariantEntity
|
|
{
|
|
public int Id { get; set; }
|
|
[Column(TypeName = "sql_variant")]
|
|
public object? Value { get; set; }
|
|
}
|
|
}
|
|
|
|
public abstract class JetComplexType(JetModelBuilderFixture fixture) : RelationalComplexTypeTestBase(fixture), IClassFixture<JetModelBuilderFixture>;
|
|
|
|
public abstract class JetInheritance(JetModelBuilderFixture fixture) : RelationalInheritanceTestBase(fixture), IClassFixture<JetModelBuilderFixture>
|
|
{
|
|
[ConditionalFact] // #7240
|
|
public void Can_use_shadow_FK_that_collides_with_convention_shadow_FK_on_other_derived_type()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<Child>();
|
|
modelBuilder.Entity<Parent>()
|
|
.HasOne(p => p.A)
|
|
.WithOne()
|
|
.HasForeignKey<DisjointChildSubclass1>("ParentId");
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var property1 = model.FindEntityType(typeof(DisjointChildSubclass1))!.FindProperty("ParentId")!;
|
|
Assert.True(property1.IsForeignKey());
|
|
Assert.Equal("ParentId", property1.GetColumnName());
|
|
var property2 = model.FindEntityType(typeof(DisjointChildSubclass2))!.FindProperty("ParentId")!;
|
|
Assert.True(property2.IsForeignKey());
|
|
Assert.Equal("ParentId", property2.GetColumnName());
|
|
Assert.Equal("DisjointChildSubclass2_ParentId", property2.GetColumnName(StoreObjectIdentifier.Table(nameof(Child))));
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public void Inherited_clr_properties_are_mapped_to_the_same_column()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<ChildBase>();
|
|
modelBuilder.Ignore<Child>();
|
|
modelBuilder.Entity<DisjointChildSubclass1>();
|
|
modelBuilder.Entity<DisjointChildSubclass2>();
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var property1 = model.FindEntityType(typeof(DisjointChildSubclass1))!.FindProperty(nameof(Child.Name))!;
|
|
Assert.Equal(nameof(Child.Name), property1.GetColumnName());
|
|
var property2 = model.FindEntityType(typeof(DisjointChildSubclass2))!.FindProperty(nameof(Child.Name))!;
|
|
Assert.Equal(nameof(Child.Name), property2.GetColumnName());
|
|
}
|
|
|
|
[ConditionalFact] //Issue#10659
|
|
public void Index_convention_run_for_fk_when_derived_type_discovered_before_base_type()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Ignore<Order>();
|
|
modelBuilder.Entity<CustomerDetails>();
|
|
modelBuilder.Entity<DetailsBase>();
|
|
|
|
var index = modelBuilder.Model.FindEntityType(typeof(CustomerDetails))!.GetIndexes().Single();
|
|
|
|
Assert.Equal("[CustomerId] IS NOT NULL", index.GetFilter());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public void Index_convention_sets_filter_for_unique_index_when_base_type_changed()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Ignore<Customer>();
|
|
modelBuilder.Entity<CustomerDetails>()
|
|
.HasIndex(e => e.CustomerId)
|
|
.IsUnique();
|
|
|
|
modelBuilder.Entity<DetailsBase>();
|
|
|
|
var index = modelBuilder.Model.FindEntityType(typeof(CustomerDetails))!.GetIndexes().Single();
|
|
|
|
Assert.Equal("[CustomerId] IS NOT NULL", index.GetFilter());
|
|
|
|
modelBuilder.Ignore<DetailsBase>();
|
|
|
|
Assert.Null(index.GetFilter());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Can_override_TPC_with_TPH()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
|
|
modelBuilder.Entity<P>();
|
|
modelBuilder.Entity<T>();
|
|
modelBuilder.Entity<Q>();
|
|
modelBuilder.Entity<PBase>()
|
|
.UseTpcMappingStrategy()
|
|
.UseTphMappingStrategy();
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
Assert.Equal("Discriminator", model.FindEntityType(typeof(PBase))!.GetDiscriminatorPropertyName());
|
|
Assert.Equal(nameof(PBase), model.FindEntityType(typeof(PBase))!.GetDiscriminatorValue());
|
|
Assert.Equal(nameof(P), model.FindEntityType(typeof(P))!.GetDiscriminatorValue());
|
|
Assert.Equal(nameof(Q), model.FindEntityType(typeof(Q))!.GetDiscriminatorValue());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void TPT_identifying_FK_is_created_only_on_declaring_table()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<BigMak>()
|
|
.Ignore(b => b.Bun)
|
|
.Ignore(b => b.Pickles);
|
|
modelBuilder.Entity<Ingredient>(
|
|
b =>
|
|
{
|
|
b.ToTable("Ingredients");
|
|
b.Ignore(i => i.BigMak);
|
|
});
|
|
modelBuilder.Entity<Bun>(
|
|
b =>
|
|
{
|
|
b.ToTable("Buns");
|
|
b.HasOne(i => i.BigMak).WithOne().HasForeignKey<Bun>(i => i.Id);
|
|
});
|
|
modelBuilder.Entity<SesameBun>(
|
|
b =>
|
|
{
|
|
b.ToTable("SesameBuns");
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var principalType = model.FindEntityType(typeof(BigMak))!;
|
|
Assert.Empty(principalType.GetForeignKeys());
|
|
Assert.Empty(principalType.GetIndexes());
|
|
Assert.Null(principalType.FindDiscriminatorProperty());
|
|
|
|
var ingredientType = model.FindEntityType(typeof(Ingredient))!;
|
|
|
|
var bunType = model.FindEntityType(typeof(Bun))!;
|
|
Assert.Empty(bunType.GetIndexes());
|
|
Assert.Null(bunType.FindDiscriminatorProperty());
|
|
var bunFk = bunType.GetDeclaredForeignKeys().Single(fk => !fk.IsBaseLinking());
|
|
Assert.Equal("FK_Buns_BigMak_Id", bunFk.GetConstraintName());
|
|
Assert.Equal(
|
|
"FK_Buns_BigMak_Id", bunFk.GetConstraintName(
|
|
StoreObjectIdentifier.Create(bunType, StoreObjectType.Table)!.Value,
|
|
StoreObjectIdentifier.Create(principalType, StoreObjectType.Table)!.Value));
|
|
Assert.Single(bunFk.GetMappedConstraints());
|
|
|
|
var bunLinkingFk = bunType.GetDeclaredForeignKeys().Single(fk => fk.IsBaseLinking());
|
|
Assert.Equal("FK_Buns_Ingredients_Id", bunLinkingFk.GetConstraintName());
|
|
Assert.Equal(
|
|
"FK_Buns_Ingredients_Id", bunLinkingFk.GetConstraintName(
|
|
StoreObjectIdentifier.Create(bunType, StoreObjectType.Table)!.Value,
|
|
StoreObjectIdentifier.Create(ingredientType, StoreObjectType.Table)!.Value));
|
|
Assert.Single(bunLinkingFk.GetMappedConstraints());
|
|
|
|
var sesameBunType = model.FindEntityType(typeof(SesameBun))!;
|
|
Assert.Empty(sesameBunType.GetIndexes());
|
|
var sesameBunFk = sesameBunType.GetDeclaredForeignKeys().Single();
|
|
Assert.True(sesameBunFk.IsBaseLinking());
|
|
Assert.Equal("FK_SesameBuns_Buns_Id", sesameBunFk.GetConstraintName());
|
|
Assert.Equal(
|
|
"FK_SesameBuns_Buns_Id", sesameBunFk.GetConstraintName(
|
|
StoreObjectIdentifier.Create(sesameBunType, StoreObjectType.Table)!.Value,
|
|
StoreObjectIdentifier.Create(bunType, StoreObjectType.Table)!.Value));
|
|
Assert.Single(sesameBunFk.GetMappedConstraints());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void TPC_identifying_FKs_are_created_on_all_tables()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<BigMak>()
|
|
.Ignore(b => b.Bun)
|
|
.Ignore(b => b.Pickles);
|
|
modelBuilder.Entity<Ingredient>(
|
|
b =>
|
|
{
|
|
b.ToTable("Ingredients");
|
|
b.Ignore(i => i.BigMak);
|
|
b.HasIndex(e => e.BurgerId);
|
|
b.UseTpcMappingStrategy();
|
|
});
|
|
modelBuilder.Entity<Bun>(
|
|
b =>
|
|
{
|
|
b.ToTable("Buns");
|
|
b.HasOne(i => i.BigMak).WithOne().HasForeignKey<Bun>(i => i.Id);
|
|
b.UseTpcMappingStrategy();
|
|
});
|
|
modelBuilder.Entity<SesameBun>(
|
|
b =>
|
|
{
|
|
b.ToTable("SesameBuns");
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var principalType = model.FindEntityType(typeof(BigMak))!;
|
|
Assert.Empty(principalType.GetForeignKeys());
|
|
Assert.Empty(principalType.GetIndexes());
|
|
Assert.Null(principalType.FindDiscriminatorProperty());
|
|
|
|
var bunType = model.FindEntityType(typeof(Bun))!;
|
|
Assert.Empty(bunType.GetDeclaredIndexes());
|
|
Assert.Null(bunType.FindDiscriminatorProperty());
|
|
var bunFk = bunType.GetDeclaredForeignKeys().Single();
|
|
Assert.Equal("FK_Buns_BigMak_Id", bunFk.GetConstraintName());
|
|
Assert.Equal(
|
|
"FK_Buns_BigMak_Id", bunFk.GetConstraintName(
|
|
StoreObjectIdentifier.Create(bunType, StoreObjectType.Table)!.Value,
|
|
StoreObjectIdentifier.Create(principalType, StoreObjectType.Table)!.Value));
|
|
Assert.Equal(2, bunFk.GetMappedConstraints().Count());
|
|
|
|
Assert.DoesNotContain(bunType.GetDeclaredForeignKeys(), fk => fk.IsBaseLinking());
|
|
|
|
var sesameBunType = model.FindEntityType(typeof(SesameBun))!;
|
|
Assert.Empty(sesameBunType.GetDeclaredIndexes());
|
|
Assert.Empty(sesameBunType.GetDeclaredForeignKeys());
|
|
Assert.Equal(
|
|
"FK_SesameBuns_BigMak_Id", bunFk.GetConstraintName(
|
|
StoreObjectIdentifier.Create(sesameBunType, StoreObjectType.Table)!.Value,
|
|
StoreObjectIdentifier.Create(principalType, StoreObjectType.Table)!.Value));
|
|
|
|
var ingredientType = model.FindEntityType(typeof(Ingredient))!;
|
|
var ingredientIndex = ingredientType.GetDeclaredIndexes().Single();
|
|
Assert.Equal("IX_Ingredients_BurgerId", ingredientIndex.GetDatabaseName());
|
|
Assert.Equal(
|
|
"IX_SesameBuns_BurgerId",
|
|
ingredientIndex.GetDatabaseName(StoreObjectIdentifier.Create(sesameBunType, StoreObjectType.Table)!.Value));
|
|
Assert.Equal(
|
|
"IX_Buns_BurgerId",
|
|
ingredientIndex.GetDatabaseName(StoreObjectIdentifier.Create(bunType, StoreObjectType.Table)!.Value));
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void TPT_index_can_use_inherited_properties()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<BigMak>()
|
|
.Ignore(b => b.Bun)
|
|
.Ignore(b => b.Pickles);
|
|
modelBuilder.Entity<Ingredient>(
|
|
b =>
|
|
{
|
|
b.ToTable("Ingredients");
|
|
b.Property<int?>("NullableProp");
|
|
b.Ignore(i => i.BigMak);
|
|
});
|
|
modelBuilder.Entity<Bun>(
|
|
b =>
|
|
{
|
|
b.ToTable("Buns");
|
|
b.HasIndex(bun => bun.BurgerId);
|
|
b.HasIndex("NullableProp");
|
|
b.HasOne(i => i.BigMak).WithOne().HasForeignKey<Bun>(i => i.Id);
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var bunType = model.FindEntityType(typeof(Bun))!;
|
|
Assert.All(bunType.GetIndexes(), i => Assert.Null(i.GetFilter()));
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public void Can_add_check_constraints()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<Child>()
|
|
.HasBaseType(null)
|
|
.ToTable(tb => tb.HasCheckConstraint("CK_ChildBase_LargeId", "Id > 1000").HasName("CK_LargeId"));
|
|
modelBuilder.Entity<ChildBase>()
|
|
.ToTable(
|
|
tb =>
|
|
{
|
|
tb.HasCheckConstraint("PositiveId", "Id > 0");
|
|
tb.HasCheckConstraint("CK_ChildBase_LargeId", "Id > 1000");
|
|
});
|
|
modelBuilder.Entity<Child>()
|
|
.HasBaseType<ChildBase>();
|
|
modelBuilder.Entity<DisjointChildSubclass1>();
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var @base = model.FindEntityType(typeof(ChildBase))!;
|
|
Assert.Equal(2, @base.GetCheckConstraints().Count());
|
|
|
|
var firstCheckConstraint = @base.FindCheckConstraint("PositiveId")!;
|
|
Assert.Equal("PositiveId", firstCheckConstraint.ModelName);
|
|
Assert.Equal("Id > 0", firstCheckConstraint.Sql);
|
|
Assert.Equal("PositiveId", firstCheckConstraint.Name);
|
|
|
|
var secondCheckConstraint = @base.FindCheckConstraint("CK_ChildBase_LargeId")!;
|
|
Assert.Equal("CK_ChildBase_LargeId", secondCheckConstraint.ModelName);
|
|
Assert.Equal("Id > 1000", secondCheckConstraint.Sql);
|
|
Assert.Equal("CK_LargeId", secondCheckConstraint.Name);
|
|
|
|
var child = model.FindEntityType(typeof(Child))!;
|
|
Assert.Equal(@base.GetCheckConstraints(), child.GetCheckConstraints());
|
|
Assert.Empty(child.GetDeclaredCheckConstraints());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public void Adding_conflicting_check_constraint_to_derived_type_throws()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<ChildBase>()
|
|
.ToTable(tb => tb.HasCheckConstraint("LargeId", "Id > 100").HasName("CK_LargeId"));
|
|
|
|
Assert.Equal(
|
|
RelationalStrings.DuplicateCheckConstraint("LargeId", nameof(Child), nameof(ChildBase)),
|
|
Assert.Throws<InvalidOperationException>(
|
|
() => modelBuilder.Entity<Child>().ToTable(tb => tb.HasCheckConstraint("LargeId", "Id > 1000"))).Message);
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public void Adding_conflicting_check_constraint_to_derived_type_before_base_throws()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<Child>()
|
|
.HasBaseType(null)
|
|
.ToTable(tb => tb.HasCheckConstraint("LargeId", "Id > 1000"));
|
|
modelBuilder.Entity<ChildBase>()
|
|
.ToTable(tb => tb.HasCheckConstraint("LargeId", "Id > 100").HasName("CK_LargeId"));
|
|
|
|
Assert.Equal(
|
|
RelationalStrings.DuplicateCheckConstraint("LargeId", nameof(Child), nameof(ChildBase)),
|
|
Assert.Throws<InvalidOperationException>(
|
|
() => modelBuilder.Entity<Child>().HasBaseType<ChildBase>()).Message);
|
|
}
|
|
|
|
protected class Parent
|
|
{
|
|
public int Id { get; set; }
|
|
public DisjointChildSubclass1? A { get; set; }
|
|
public IList<DisjointChildSubclass2>? B { get; set; }
|
|
}
|
|
|
|
protected abstract class ChildBase
|
|
{
|
|
public int Id { get; set; }
|
|
}
|
|
|
|
protected abstract class Child : ChildBase
|
|
{
|
|
public string? Name { get; set; }
|
|
}
|
|
|
|
protected class DisjointChildSubclass1 : Child;
|
|
|
|
protected class DisjointChildSubclass2 : Child;
|
|
}
|
|
|
|
public abstract class JetOneToMany(JetModelBuilderFixture fixture) : RelationalOneToManyTestBase(fixture), IClassFixture<JetModelBuilderFixture>
|
|
{
|
|
[ConditionalFact]
|
|
public virtual void Shadow_foreign_keys_to_generic_types_have_terrible_names_that_should_not_change()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
|
|
modelBuilder.Entity<EventBase>().ToTable("Events");
|
|
modelBuilder.Entity<Activity<Company>>().ToTable("CompanyActivities");
|
|
modelBuilder.Entity<Activity<User>>().ToTable("UserActivities");
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var companyActivityEventType = model.FindEntityType(typeof(ActivityEvent<Company>))!;
|
|
var eventTable = StoreObjectIdentifier.Create(companyActivityEventType, StoreObjectType.Table)!.Value;
|
|
var companyActivityEventFk = companyActivityEventType.GetForeignKeys().Single();
|
|
var companyActivityEventFkProperty = companyActivityEventFk.Properties.Single();
|
|
Assert.Equal("Activity<Company>Id", companyActivityEventFkProperty.GetColumnName(eventTable));
|
|
Assert.Equal("FK_Events_CompanyActivities_Activity<Company>Id", companyActivityEventFk.GetConstraintName());
|
|
Assert.Equal(
|
|
"FK_Events_CompanyActivities_Activity<Company>Id", companyActivityEventFk.GetConstraintName(
|
|
eventTable,
|
|
StoreObjectIdentifier.Create(companyActivityEventFk.PrincipalEntityType, StoreObjectType.Table)!.Value));
|
|
|
|
var userActivityEventType = model.FindEntityType(typeof(ActivityEvent<User>))!;
|
|
var userActivityEventFk = userActivityEventType.GetForeignKeys().Single();
|
|
var userActivityEventFkProperty = userActivityEventFk.Properties.Single();
|
|
Assert.Equal("Activity<User>Id", userActivityEventFkProperty.GetColumnName(eventTable));
|
|
Assert.Equal("FK_Events_UserActivities_Activity<User>Id", userActivityEventFk.GetConstraintName());
|
|
Assert.Equal(
|
|
"FK_Events_UserActivities_Activity<User>Id", userActivityEventFk.GetConstraintName(
|
|
eventTable,
|
|
StoreObjectIdentifier.Create(userActivityEventFk.PrincipalEntityType, StoreObjectType.Table)!.Value));
|
|
}
|
|
|
|
protected abstract class EventBase
|
|
{
|
|
public string? Id { get; set; }
|
|
}
|
|
|
|
protected class Activity<T>
|
|
{
|
|
public string? Id { get; set; }
|
|
public virtual List<ActivityEvent<T>> Events { get; } = null!;
|
|
}
|
|
|
|
protected class ActivityEvent<TTarget> : EventBase;
|
|
|
|
protected class Company;
|
|
|
|
protected class User;
|
|
}
|
|
|
|
public abstract class JetManyToOne(JetModelBuilderFixture fixture) : RelationalManyToOneTestBase(fixture), IClassFixture<JetModelBuilderFixture>;
|
|
|
|
public abstract class JetOneToOne(JetModelBuilderFixture fixture) : RelationalOneToOneTestBase(fixture), IClassFixture<JetModelBuilderFixture>;
|
|
|
|
public abstract class JetManyToMany(JetModelBuilderFixture fixture) : RelationalManyToManyTestBase(fixture), IClassFixture<JetModelBuilderFixture>
|
|
{
|
|
[ConditionalFact]
|
|
public virtual void Join_entity_type_uses_same_schema()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
|
|
modelBuilder.Entity<Category>().ToTable("Category", "mySchema").Ignore(c => c.ProductCategories);
|
|
modelBuilder.Entity<Product>().ToTable("Product", "mySchema");
|
|
modelBuilder.Entity<CategoryBase>();
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var productType = model.FindEntityType(typeof(Product))!;
|
|
var categoryType = model.FindEntityType(typeof(Category))!;
|
|
|
|
var categoriesNavigation = productType.GetSkipNavigations().Single();
|
|
var productsNavigation = categoryType.GetSkipNavigations().Single();
|
|
|
|
var categoriesFk = categoriesNavigation.ForeignKey;
|
|
var productsFk = productsNavigation.ForeignKey;
|
|
var productCategoryType = categoriesFk.DeclaringEntityType;
|
|
|
|
Assert.Equal(typeof(Dictionary<string, object>), productCategoryType.ClrType);
|
|
Assert.Equal("mySchema", productCategoryType.GetSchema());
|
|
Assert.Same(categoriesFk, productCategoryType.GetForeignKeys().Last());
|
|
Assert.Same(productsFk, productCategoryType.GetForeignKeys().First());
|
|
Assert.Equal(2, productCategoryType.GetForeignKeys().Count());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Join_entity_type_uses_default_schema_if_related_are_different()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
|
|
modelBuilder.Entity<Category>().ToTable("Category").Ignore(c => c.ProductCategories);
|
|
modelBuilder.Entity<Product>().ToTable("Product", "dbo");
|
|
modelBuilder.Entity<CategoryBase>();
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var productType = model.FindEntityType(typeof(Product))!;
|
|
var categoryType = model.FindEntityType(typeof(Category))!;
|
|
|
|
var categoriesNavigation = productType.GetSkipNavigations().Single();
|
|
var productsNavigation = categoryType.GetSkipNavigations().Single();
|
|
|
|
var categoriesFk = categoriesNavigation.ForeignKey;
|
|
var productsFk = productsNavigation.ForeignKey;
|
|
var productCategoryType = categoriesFk.DeclaringEntityType;
|
|
|
|
Assert.Equal(typeof(Dictionary<string, object>), productCategoryType.ClrType);
|
|
Assert.Null(productCategoryType.GetSchema());
|
|
Assert.Same(categoriesFk, productCategoryType.GetForeignKeys().Last());
|
|
Assert.Same(productsFk, productCategoryType.GetForeignKeys().First());
|
|
Assert.Equal(2, productCategoryType.GetForeignKeys().Count());
|
|
}
|
|
}
|
|
|
|
public abstract class JetOwnedTypes(JetModelBuilderFixture fixture) : RelationalOwnedTypesTestBase(fixture), IClassFixture<JetModelBuilderFixture>
|
|
{
|
|
[ConditionalFact]
|
|
public virtual void Owned_types_use_table_splitting_by_default()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
|
|
modelBuilder.Entity<Book>().OwnsOne(
|
|
b => b.AlternateLabel,
|
|
b =>
|
|
{
|
|
b.Ignore(l => l.Book);
|
|
b.OwnsOne(
|
|
l => l.AnotherBookLabel,
|
|
ab =>
|
|
{
|
|
ab.Property(l => l.BookId).HasColumnName("BookId2");
|
|
ab.Ignore(l => l.Book);
|
|
ab.OwnsOne(
|
|
s => s.SpecialBookLabel,
|
|
s =>
|
|
{
|
|
s.Property(l => l.BookId).HasColumnName("BookId2");
|
|
s.Ignore(l => l.Book);
|
|
s.Ignore(l => l.BookLabel);
|
|
});
|
|
});
|
|
});
|
|
|
|
modelBuilder.Entity<Book>().OwnsOne(b => b.Label)
|
|
.Ignore(l => l.Book)
|
|
.OwnsOne(l => l.SpecialBookLabel)
|
|
.Ignore(l => l.Book)
|
|
.OwnsOne(a => a.AnotherBookLabel)
|
|
.Ignore(l => l.Book);
|
|
|
|
modelBuilder.Entity<Book>().OwnsOne(b => b.Label)
|
|
.OwnsOne(l => l.AnotherBookLabel)
|
|
.Ignore(l => l.Book)
|
|
.OwnsOne(a => a.SpecialBookLabel)
|
|
.Ignore(l => l.Book)
|
|
.Ignore(l => l.BookLabel);
|
|
|
|
modelBuilder.Entity<Book>().OwnsOne(
|
|
b => b.AlternateLabel,
|
|
b =>
|
|
{
|
|
b.Ignore(l => l.Book);
|
|
b.OwnsOne(
|
|
l => l.SpecialBookLabel,
|
|
ab =>
|
|
{
|
|
ab.Property(l => l.BookId).HasColumnName("BookId2");
|
|
ab.Ignore(l => l.Book);
|
|
ab.OwnsOne(
|
|
s => s.AnotherBookLabel,
|
|
s =>
|
|
{
|
|
s.Property(l => l.BookId).HasColumnName("BookId2");
|
|
s.Ignore(l => l.Book);
|
|
});
|
|
});
|
|
});
|
|
|
|
var model = (IModel)modelBuilder.Model;
|
|
var book = model.FindEntityType(typeof(Book))!;
|
|
var bookOwnership1 = book.FindNavigation(nameof(Book.Label))!.ForeignKey;
|
|
var bookOwnership2 = book.FindNavigation(nameof(Book.AlternateLabel))!.ForeignKey;
|
|
var bookLabel1Ownership1 = bookOwnership1.DeclaringEntityType.FindNavigation(nameof(BookLabel.AnotherBookLabel))!.ForeignKey;
|
|
var bookLabel1Ownership2 = bookOwnership1.DeclaringEntityType.FindNavigation(nameof(BookLabel.SpecialBookLabel))!.ForeignKey;
|
|
var bookLabel2Ownership1 = bookOwnership2.DeclaringEntityType.FindNavigation(nameof(BookLabel.AnotherBookLabel))!.ForeignKey;
|
|
var bookLabel2Ownership2 = bookOwnership2.DeclaringEntityType.FindNavigation(nameof(BookLabel.SpecialBookLabel))!.ForeignKey;
|
|
|
|
Assert.Equal(book.GetTableName(), bookOwnership1.DeclaringEntityType.GetTableName());
|
|
Assert.Equal(book.GetTableName(), bookOwnership2.DeclaringEntityType.GetTableName());
|
|
Assert.Equal(book.GetTableName(), bookLabel1Ownership1.DeclaringEntityType.GetTableName());
|
|
Assert.Equal(book.GetTableName(), bookLabel1Ownership2.DeclaringEntityType.GetTableName());
|
|
Assert.Equal(book.GetTableName(), bookLabel2Ownership1.DeclaringEntityType.GetTableName());
|
|
Assert.Equal(book.GetTableName(), bookLabel2Ownership2.DeclaringEntityType.GetTableName());
|
|
|
|
Assert.NotSame(bookOwnership1.DeclaringEntityType, bookOwnership2.DeclaringEntityType);
|
|
Assert.Single(bookOwnership1.DeclaringEntityType.GetForeignKeys());
|
|
Assert.Single(bookOwnership1.DeclaringEntityType.GetForeignKeys());
|
|
|
|
Assert.NotSame(bookLabel1Ownership1.DeclaringEntityType, bookLabel2Ownership1.DeclaringEntityType);
|
|
Assert.NotSame(bookLabel1Ownership2.DeclaringEntityType, bookLabel2Ownership2.DeclaringEntityType);
|
|
Assert.Single(bookLabel1Ownership1.DeclaringEntityType.GetForeignKeys());
|
|
Assert.Single(bookLabel1Ownership2.DeclaringEntityType.GetForeignKeys());
|
|
Assert.Single(bookLabel2Ownership1.DeclaringEntityType.GetForeignKeys());
|
|
Assert.Single(bookLabel2Ownership2.DeclaringEntityType.GetForeignKeys());
|
|
|
|
Assert.Equal(2, model.GetEntityTypes().Count(e => e.ClrType == typeof(BookLabel)));
|
|
Assert.Equal(4, model.GetEntityTypes().Count(e => e.ClrType == typeof(AnotherBookLabel)));
|
|
Assert.Equal(4, model.GetEntityTypes().Count(e => e.ClrType == typeof(SpecialBookLabel)));
|
|
|
|
Assert.Null(
|
|
bookOwnership1.DeclaringEntityType.FindProperty(nameof(BookLabel.Id))!
|
|
.GetColumnName(StoreObjectIdentifier.Table("Label")));
|
|
Assert.Null(
|
|
bookLabel2Ownership1.DeclaringEntityType.FindProperty(nameof(BookLabel.Id))!
|
|
.GetColumnName(StoreObjectIdentifier.Table("AlternateLabel")));
|
|
|
|
modelBuilder.Entity<Book>().OwnsOne(b => b.Label).ToTable("Label");
|
|
modelBuilder.Entity<Book>().OwnsOne(b => b.AlternateLabel).ToTable("AlternateLabel");
|
|
|
|
model = modelBuilder.FinalizeModel();
|
|
|
|
Assert.Equal(
|
|
nameof(BookLabel.Id),
|
|
bookOwnership1.DeclaringEntityType.FindProperty(nameof(BookLabel.Id))!
|
|
.GetColumnName(StoreObjectIdentifier.Table("Label")));
|
|
Assert.Equal(
|
|
nameof(BookLabel.AnotherBookLabel) + "_" + nameof(BookLabel.Id),
|
|
bookLabel2Ownership1.DeclaringEntityType.FindProperty(nameof(BookLabel.Id))!
|
|
.GetColumnName(StoreObjectIdentifier.Table("AlternateLabel")));
|
|
|
|
var alternateTable = model.GetRelationalModel().FindTable("AlternateLabel", null)!;
|
|
var bookId = alternateTable.FindColumn("BookId2")!;
|
|
|
|
Assert.Equal(4, bookId.PropertyMappings.Count());
|
|
Assert.All(bookId.PropertyMappings, m => Assert.Equal(ValueGenerated.OnUpdateSometimes, m.Property.ValueGenerated));
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Owned_types_can_be_mapped_to_different_tables()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
var model = modelBuilder.Model;
|
|
|
|
modelBuilder.Entity<Book>(
|
|
bb =>
|
|
{
|
|
bb.ToTable(
|
|
"BT", "BS", t =>
|
|
{
|
|
t.ExcludeFromMigrations();
|
|
|
|
Assert.Equal("BT", t.Name);
|
|
Assert.Equal("BS", t.Schema);
|
|
});
|
|
bb.OwnsOne(
|
|
b => b.AlternateLabel, tb =>
|
|
{
|
|
tb.Ignore(l => l.Book);
|
|
tb.WithOwner()
|
|
.HasConstraintName("AlternateLabelFK");
|
|
tb.ToTable("TT", "TS");
|
|
tb.OwnsOne(
|
|
l => l.AnotherBookLabel, ab =>
|
|
{
|
|
ab.Ignore(l => l.Book);
|
|
ab.ToTable(
|
|
"AT1", "AS1", t =>
|
|
{
|
|
t.ExcludeFromMigrations(false);
|
|
|
|
Assert.Equal("AT1", t.Name);
|
|
Assert.Equal("AS1", t.Schema);
|
|
});
|
|
ab.OwnsOne(s => s.SpecialBookLabel)
|
|
.ToTable("ST11", "SS11")
|
|
.Ignore(l => l.Book)
|
|
.Ignore(l => l.BookLabel);
|
|
|
|
ab.OwnedEntityType.FindNavigation(nameof(BookLabel.SpecialBookLabel))!
|
|
.AddAnnotation("Foo", "Bar");
|
|
});
|
|
tb.OwnsOne(
|
|
l => l.SpecialBookLabel, sb =>
|
|
{
|
|
sb.Ignore(l => l.Book);
|
|
sb.ToTable("ST2", "SS2");
|
|
sb.OwnsOne(s => s.AnotherBookLabel)
|
|
.ToTable("AT21", "AS21")
|
|
.Ignore(l => l.Book);
|
|
});
|
|
});
|
|
bb.OwnsOne(
|
|
b => b.Label, lb =>
|
|
{
|
|
lb.Ignore(l => l.Book);
|
|
lb.ToTable("LT", "LS");
|
|
lb.OwnsOne(
|
|
l => l.SpecialBookLabel, sb =>
|
|
{
|
|
sb.Ignore(l => l.Book);
|
|
sb.ToTable("ST1", "SS1");
|
|
sb.OwnsOne(a => a.AnotherBookLabel)
|
|
.ToTable("AT11", "AS11")
|
|
.Ignore(l => l.Book);
|
|
});
|
|
lb.OwnsOne(
|
|
l => l.AnotherBookLabel, ab =>
|
|
{
|
|
ab.Ignore(l => l.Book);
|
|
ab.ToTable("AT2", "AS2");
|
|
ab.OwnsOne(a => a.SpecialBookLabel)
|
|
.ToTable("ST21", "SS21")
|
|
.Ignore(l => l.BookLabel)
|
|
.Ignore(l => l.Book);
|
|
});
|
|
});
|
|
});
|
|
|
|
modelBuilder.FinalizeModel();
|
|
|
|
var book = model.FindEntityType(typeof(Book))!;
|
|
var bookOwnership1 = book.FindNavigation(nameof(Book.Label))!.ForeignKey;
|
|
var bookOwnership2 = book.FindNavigation(nameof(Book.AlternateLabel))!.ForeignKey;
|
|
var bookLabel1Ownership1 = bookOwnership1.DeclaringEntityType.FindNavigation(nameof(BookLabel.AnotherBookLabel))!.ForeignKey;
|
|
var bookLabel1Ownership2 = bookOwnership1.DeclaringEntityType.FindNavigation(nameof(BookLabel.SpecialBookLabel))!.ForeignKey;
|
|
var bookLabel2Ownership1 = bookOwnership2.DeclaringEntityType.FindNavigation(nameof(BookLabel.AnotherBookLabel))!.ForeignKey;
|
|
var bookLabel2Ownership2 = bookOwnership2.DeclaringEntityType.FindNavigation(nameof(BookLabel.SpecialBookLabel))!.ForeignKey;
|
|
var bookLabel1Ownership11 = bookLabel1Ownership1.DeclaringEntityType.FindNavigation(nameof(BookLabel.SpecialBookLabel))!
|
|
.ForeignKey;
|
|
var bookLabel1Ownership21 = bookLabel1Ownership2.DeclaringEntityType.FindNavigation(nameof(BookLabel.AnotherBookLabel))!
|
|
.ForeignKey;
|
|
var bookLabel2Ownership11 = bookLabel2Ownership1.DeclaringEntityType.FindNavigation(nameof(BookLabel.SpecialBookLabel))!
|
|
.ForeignKey;
|
|
var bookLabel2Ownership21 = bookLabel2Ownership2.DeclaringEntityType.FindNavigation(nameof(BookLabel.AnotherBookLabel))!
|
|
.ForeignKey;
|
|
|
|
Assert.Equal("AlternateLabelFK", bookOwnership2.GetConstraintName());
|
|
|
|
Assert.Equal("BS", book.GetSchema());
|
|
Assert.Equal("BT", book.GetTableName());
|
|
Assert.True(book.IsTableExcludedFromMigrations());
|
|
Assert.Equal("LS", bookOwnership1.DeclaringEntityType.GetSchema());
|
|
Assert.Equal("LT", bookOwnership1.DeclaringEntityType.GetTableName());
|
|
Assert.True(bookOwnership1.DeclaringEntityType.IsTableExcludedFromMigrations());
|
|
Assert.Equal("TS", bookOwnership2.DeclaringEntityType.GetSchema());
|
|
Assert.Equal("TT", bookOwnership2.DeclaringEntityType.GetTableName());
|
|
Assert.True(bookOwnership2.DeclaringEntityType.IsTableExcludedFromMigrations());
|
|
Assert.Equal("AS2", bookLabel1Ownership1.DeclaringEntityType.GetSchema());
|
|
Assert.Equal("AT2", bookLabel1Ownership1.DeclaringEntityType.GetTableName());
|
|
Assert.Equal("SS1", bookLabel1Ownership2.DeclaringEntityType.GetSchema());
|
|
Assert.Equal("ST1", bookLabel1Ownership2.DeclaringEntityType.GetTableName());
|
|
Assert.Equal("AS1", bookLabel2Ownership1.DeclaringEntityType.GetSchema());
|
|
Assert.Equal("AT1", bookLabel2Ownership1.DeclaringEntityType.GetTableName());
|
|
Assert.False(bookLabel2Ownership1.DeclaringEntityType.IsTableExcludedFromMigrations());
|
|
Assert.Equal("SS2", bookLabel2Ownership2.DeclaringEntityType.GetSchema());
|
|
Assert.Equal("ST2", bookLabel2Ownership2.DeclaringEntityType.GetTableName());
|
|
Assert.Equal("SS21", bookLabel1Ownership11.DeclaringEntityType.GetSchema());
|
|
Assert.Equal("ST21", bookLabel1Ownership11.DeclaringEntityType.GetTableName());
|
|
Assert.Equal("AS11", bookLabel1Ownership21.DeclaringEntityType.GetSchema());
|
|
Assert.Equal("AT11", bookLabel1Ownership21.DeclaringEntityType.GetTableName());
|
|
Assert.Equal("SS11", bookLabel2Ownership11.DeclaringEntityType.GetSchema());
|
|
Assert.Equal("ST11", bookLabel2Ownership11.DeclaringEntityType.GetTableName());
|
|
Assert.Equal("AS21", bookLabel2Ownership21.DeclaringEntityType.GetSchema());
|
|
Assert.Equal("AT21", bookLabel2Ownership21.DeclaringEntityType.GetTableName());
|
|
|
|
Assert.Equal("Bar", bookLabel2Ownership11.PrincipalToDependent?["Foo"]);
|
|
|
|
Assert.NotSame(bookOwnership1.DeclaringEntityType, bookOwnership2.DeclaringEntityType);
|
|
Assert.Single(bookOwnership1.DeclaringEntityType.GetForeignKeys());
|
|
Assert.Single(bookOwnership2.DeclaringEntityType.GetForeignKeys());
|
|
|
|
Assert.NotSame(bookLabel1Ownership1.DeclaringEntityType, bookLabel2Ownership1.DeclaringEntityType);
|
|
Assert.NotSame(bookLabel1Ownership2.DeclaringEntityType, bookLabel2Ownership2.DeclaringEntityType);
|
|
Assert.Single(bookLabel1Ownership1.DeclaringEntityType.GetForeignKeys());
|
|
Assert.Single(bookLabel1Ownership2.DeclaringEntityType.GetForeignKeys());
|
|
Assert.Single(bookLabel2Ownership1.DeclaringEntityType.GetForeignKeys());
|
|
Assert.Single(bookLabel2Ownership2.DeclaringEntityType.GetForeignKeys());
|
|
|
|
Assert.NotSame(bookLabel1Ownership11.DeclaringEntityType, bookLabel2Ownership11.DeclaringEntityType);
|
|
Assert.NotSame(bookLabel1Ownership21.DeclaringEntityType, bookLabel2Ownership21.DeclaringEntityType);
|
|
Assert.Single(bookLabel1Ownership11.DeclaringEntityType.GetForeignKeys());
|
|
Assert.Single(bookLabel1Ownership21.DeclaringEntityType.GetForeignKeys());
|
|
Assert.Single(bookLabel2Ownership11.DeclaringEntityType.GetForeignKeys());
|
|
Assert.Single(bookLabel2Ownership21.DeclaringEntityType.GetForeignKeys());
|
|
|
|
Assert.Equal(2, model.GetEntityTypes().Count(e => e.ClrType == typeof(BookLabel)));
|
|
Assert.Equal(4, model.GetEntityTypes().Count(e => e.ClrType == typeof(AnotherBookLabel)));
|
|
Assert.Equal(4, model.GetEntityTypes().Count(e => e.ClrType == typeof(SpecialBookLabel)));
|
|
|
|
Assert.Equal(ValueGenerated.Never, bookOwnership1.DeclaringEntityType.FindPrimaryKey()!.Properties.Single().ValueGenerated);
|
|
Assert.Equal(ValueGenerated.Never, bookOwnership2.DeclaringEntityType.FindPrimaryKey()!.Properties.Single().ValueGenerated);
|
|
|
|
Assert.Equal(
|
|
ValueGenerated.Never, bookLabel1Ownership1.DeclaringEntityType.FindPrimaryKey()!.Properties.Single().ValueGenerated);
|
|
Assert.Equal(
|
|
ValueGenerated.Never, bookLabel1Ownership2.DeclaringEntityType.FindPrimaryKey()!.Properties.Single().ValueGenerated);
|
|
Assert.Equal(
|
|
ValueGenerated.Never, bookLabel2Ownership1.DeclaringEntityType.FindPrimaryKey()!.Properties.Single().ValueGenerated);
|
|
Assert.Equal(
|
|
ValueGenerated.Never, bookLabel2Ownership2.DeclaringEntityType.FindPrimaryKey()!.Properties.Single().ValueGenerated);
|
|
|
|
Assert.Equal(
|
|
ValueGenerated.Never, bookLabel1Ownership11.DeclaringEntityType.FindPrimaryKey()!.Properties.Single().ValueGenerated);
|
|
Assert.Equal(
|
|
ValueGenerated.Never, bookLabel1Ownership21.DeclaringEntityType.FindPrimaryKey()!.Properties.Single().ValueGenerated);
|
|
Assert.Equal(
|
|
ValueGenerated.Never, bookLabel2Ownership11.DeclaringEntityType.FindPrimaryKey()!.Properties.Single().ValueGenerated);
|
|
Assert.Equal(
|
|
ValueGenerated.Never, bookLabel2Ownership21.DeclaringEntityType.FindPrimaryKey()!.Properties.Single().ValueGenerated);
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Owned_type_collections_can_be_mapped_to_different_tables()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
var model = modelBuilder.Model;
|
|
|
|
modelBuilder.Entity<Customer>().OwnsMany(
|
|
c => c.Orders,
|
|
r =>
|
|
{
|
|
r.HasKey(o => o.OrderId);
|
|
//r.ToTable(tb => tb.IsMemoryOptimized());
|
|
r.Ignore(o => o.OrderCombination);
|
|
r.Ignore(o => o.Details);
|
|
});
|
|
|
|
var ownership = model.FindEntityType(typeof(Customer))!.FindNavigation(nameof(Customer.Orders))!.ForeignKey;
|
|
var owned = ownership.DeclaringEntityType;
|
|
Assert.True(ownership.IsOwnership);
|
|
Assert.Equal(nameof(Order.Customer), ownership.DependentToPrincipal?.Name);
|
|
Assert.Equal("FK_Order_Customer_CustomerId", ownership.GetConstraintName());
|
|
|
|
Assert.Single(owned.GetForeignKeys());
|
|
Assert.Single(owned.GetIndexes());
|
|
Assert.Equal(
|
|
new[] { nameof(Order.OrderId), nameof(Order.AnotherCustomerId), nameof(Order.CustomerId) },
|
|
owned.GetProperties().Select(p => p.GetColumnName()));
|
|
Assert.Equal(nameof(Order), owned.GetTableName());
|
|
Assert.Null(owned.GetSchema());
|
|
|
|
modelBuilder.Entity<Customer>().OwnsMany(
|
|
c => c.Orders,
|
|
r =>
|
|
{
|
|
r.WithOwner(o => o.Customer).HasConstraintName("Owned");
|
|
r.ToTable("bar", "foo");
|
|
});
|
|
|
|
Assert.Equal("bar", owned.GetTableName());
|
|
Assert.Equal("foo", owned.GetSchema());
|
|
Assert.Equal("Owned", ownership.GetConstraintName());
|
|
|
|
modelBuilder.Entity<Customer>().OwnsMany(
|
|
c => c.Orders,
|
|
r => r.ToTable("blah"));
|
|
|
|
modelBuilder.FinalizeModel();
|
|
|
|
Assert.Equal("blah", owned.GetTableName());
|
|
Assert.Null(owned.GetSchema());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Owned_type_collections_can_be_mapped_to_a_view()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
|
|
modelBuilder.Entity<Customer>().OwnsMany(
|
|
c => c.Orders,
|
|
r =>
|
|
{
|
|
r.HasKey(o => o.OrderId);
|
|
r.Ignore(o => o.OrderCombination);
|
|
r.Ignore(o => o.Details);
|
|
r.ToView("bar", "foo");
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var owner = model.FindEntityType(typeof(Customer))!;
|
|
var ownership = owner.FindNavigation(nameof(Customer.Orders))!.ForeignKey;
|
|
var owned = ownership.DeclaringEntityType;
|
|
Assert.True(ownership.IsOwnership);
|
|
Assert.Equal(nameof(Order.Customer), ownership.DependentToPrincipal?.Name);
|
|
Assert.Empty(ownership.GetMappedConstraints());
|
|
|
|
Assert.Equal(nameof(Customer), owner.GetTableName());
|
|
Assert.Null(owner.GetSchema());
|
|
|
|
Assert.Null(owned.GetForeignKeys().Single().GetConstraintName());
|
|
Assert.Single(owned.GetIndexes());
|
|
Assert.Null(owned.FindPrimaryKey()!.GetName());
|
|
Assert.Equal(
|
|
new[] { nameof(Order.OrderId), nameof(Order.AnotherCustomerId), nameof(Order.CustomerId) },
|
|
owned.GetProperties().Select(p => p.GetColumnName()));
|
|
Assert.Null(owned.GetTableName());
|
|
Assert.Null(owned.GetSchema());
|
|
Assert.Equal("bar", owned.GetViewName());
|
|
Assert.Equal("foo", owned.GetViewSchema());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Owner_can_be_mapped_to_a_view()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
|
|
modelBuilder.Entity<Customer>().OwnsMany(
|
|
c => c.Orders,
|
|
r =>
|
|
{
|
|
r.HasKey(o => o.OrderId);
|
|
r.Ignore(o => o.OrderCombination);
|
|
r.Ignore(o => o.Details);
|
|
})
|
|
.ToView("bar", "foo");
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var owner = model.FindEntityType(typeof(Customer))!;
|
|
var ownership = owner.FindNavigation(nameof(Customer.Orders))!.ForeignKey;
|
|
var owned = ownership.DeclaringEntityType;
|
|
Assert.True(ownership.IsOwnership);
|
|
Assert.Equal(nameof(Order.Customer), ownership.DependentToPrincipal?.Name);
|
|
Assert.Empty(ownership.GetMappedConstraints());
|
|
|
|
Assert.Null(owner.GetTableName());
|
|
Assert.Null(owner.GetSchema());
|
|
Assert.Equal("bar", owner.GetViewName());
|
|
Assert.Equal("foo", owner.GetViewSchema());
|
|
|
|
Assert.Null(owned.GetForeignKeys().Single().GetConstraintName());
|
|
Assert.Equal("IX_Order_CustomerId", owned.GetIndexes().Single().GetDatabaseName());
|
|
Assert.Equal("PK_Order", owned.FindPrimaryKey()!.GetName());
|
|
Assert.Equal(
|
|
new[] { nameof(Order.OrderId), nameof(Order.AnotherCustomerId), nameof(Order.CustomerId) },
|
|
owned.GetProperties().Select(p => p.GetColumnName()));
|
|
Assert.Equal(nameof(Order), owned.GetTableName());
|
|
Assert.Null(owned.GetSchema());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Json_entity_and_normal_owned_can_exist_side_by_side_on_same_entity()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
|
|
modelBuilder.Entity<JsonEntity>(
|
|
b =>
|
|
{
|
|
b.OwnsOne(x => x.OwnedReference1);
|
|
b.OwnsOne(x => x.OwnedReference2, bb => bb.ToJson("reference"));
|
|
b.OwnsMany(x => x.OwnedCollection1);
|
|
b.OwnsMany(x => x.OwnedCollection2, bb => bb.ToJson("collection"));
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var owner = model.FindEntityType(typeof(JsonEntity))!;
|
|
Assert.False(owner.IsMappedToJson());
|
|
Assert.True(owner.GetDeclaredProperties().All(x => x.GetJsonPropertyName() == null));
|
|
|
|
var ownedEntities = model.FindEntityTypes(typeof(OwnedEntity));
|
|
Assert.Equal(4, ownedEntities.Count());
|
|
Assert.Equal(2, ownedEntities.Where(e => e.IsMappedToJson()).Count());
|
|
Assert.Equal(2, ownedEntities.Where(e => e.IsOwned() && !e.IsMappedToJson()).Count());
|
|
var reference = ownedEntities.Where(e => e.GetContainerColumnName() == "reference").Single();
|
|
Assert.Equal("Date", reference.GetProperty("Date").GetJsonPropertyName());
|
|
Assert.Equal("Fraction", reference.GetProperty("Fraction").GetJsonPropertyName());
|
|
Assert.Equal("Enum", reference.GetProperty("Enum").GetJsonPropertyName());
|
|
|
|
var collection = ownedEntities.Where(e => e.GetContainerColumnName() == "collection").Single();
|
|
Assert.Equal("Date", collection.GetProperty("Date").GetJsonPropertyName());
|
|
Assert.Equal("Fraction", collection.GetProperty("Fraction").GetJsonPropertyName());
|
|
Assert.Equal("Enum", collection.GetProperty("Enum").GetJsonPropertyName());
|
|
|
|
var nonJson = ownedEntities.Where(e => !e.IsMappedToJson()).ToList();
|
|
Assert.True(nonJson.All(x => x.GetProperty("Date").GetJsonPropertyName() == null));
|
|
Assert.True(nonJson.All(x => x.GetProperty("Fraction").GetJsonPropertyName() == null));
|
|
Assert.True(nonJson.All(x => x.GetProperty("Enum").GetJsonPropertyName() == null));
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Json_entity_with_tph_inheritance()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
|
|
modelBuilder.Entity<JsonEntityInheritanceBase>(
|
|
b =>
|
|
{
|
|
b.OwnsOne(x => x.OwnedReferenceOnBase, bb => bb.ToJson("reference_on_base"));
|
|
b.OwnsMany(x => x.OwnedCollectionOnBase, bb => bb.ToJson("collection_on_base"));
|
|
});
|
|
|
|
modelBuilder.Entity<JsonEntityInheritanceDerived>(
|
|
b =>
|
|
{
|
|
b.HasBaseType<JsonEntityInheritanceBase>();
|
|
b.OwnsOne(x => x.OwnedReferenceOnDerived, bb => bb.ToJson("reference_on_derived"));
|
|
b.OwnsMany(x => x.OwnedCollectionOnDerived, bb => bb.ToJson("collection_on_derived"));
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var ownedEntities = model.FindEntityTypes(typeof(OwnedEntity)).ToList();
|
|
Assert.Equal(4, ownedEntities.Count());
|
|
|
|
foreach (var ownedEntity in ownedEntities)
|
|
{
|
|
Assert.Equal("Date", ownedEntity.GetProperty("Date").GetJsonPropertyName());
|
|
Assert.Equal("Fraction", ownedEntity.GetProperty("Fraction").GetJsonPropertyName());
|
|
Assert.Equal("Enum", ownedEntity.GetProperty("Enum").GetJsonPropertyName());
|
|
}
|
|
|
|
var jsonColumnNames = ownedEntities.Select(x => x.GetContainerColumnName()).OrderBy(x => x).ToList();
|
|
Assert.Equal("collection_on_base", jsonColumnNames[0]);
|
|
Assert.Equal("collection_on_derived", jsonColumnNames[1]);
|
|
Assert.Equal("reference_on_base", jsonColumnNames[2]);
|
|
Assert.Equal("reference_on_derived", jsonColumnNames[3]);
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Json_entity_with_nested_structure_same_property_names()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<JsonEntityWithNesting>(
|
|
b =>
|
|
{
|
|
b.OwnsOne(
|
|
x => x.OwnedReference1, bb =>
|
|
{
|
|
bb.ToJson("ref1");
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
});
|
|
|
|
b.OwnsOne(
|
|
x => x.OwnedReference2, bb =>
|
|
{
|
|
bb.ToJson("ref2");
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
});
|
|
|
|
b.OwnsMany(
|
|
x => x.OwnedCollection1, bb =>
|
|
{
|
|
bb.ToJson("col1");
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
});
|
|
|
|
b.OwnsMany(
|
|
x => x.OwnedCollection2, bb =>
|
|
{
|
|
bb.ToJson("col2");
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
});
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var outerOwnedEntities = model.FindEntityTypes(typeof(OwnedEntityExtraLevel));
|
|
Assert.Equal(4, outerOwnedEntities.Count());
|
|
|
|
foreach (var outerOwnedEntity in outerOwnedEntities)
|
|
{
|
|
Assert.Equal("Date", outerOwnedEntity.GetProperty("Date").GetJsonPropertyName());
|
|
Assert.Equal("Fraction", outerOwnedEntity.GetProperty("Fraction").GetJsonPropertyName());
|
|
Assert.Equal("Enum", outerOwnedEntity.GetProperty("Enum").GetJsonPropertyName());
|
|
Assert.Equal(
|
|
"Reference1",
|
|
outerOwnedEntity.GetNavigations().Single(n => n.Name == "Reference1").TargetEntityType.GetJsonPropertyName());
|
|
Assert.Equal(
|
|
"Reference2",
|
|
outerOwnedEntity.GetNavigations().Single(n => n.Name == "Reference2").TargetEntityType.GetJsonPropertyName());
|
|
Assert.Equal(
|
|
"Collection1",
|
|
outerOwnedEntity.GetNavigations().Single(n => n.Name == "Collection1").TargetEntityType.GetJsonPropertyName());
|
|
Assert.Equal(
|
|
"Collection2",
|
|
outerOwnedEntity.GetNavigations().Single(n => n.Name == "Collection2").TargetEntityType.GetJsonPropertyName());
|
|
}
|
|
|
|
var ownedEntities = model.FindEntityTypes(typeof(OwnedEntity));
|
|
Assert.Equal(16, ownedEntities.Count());
|
|
|
|
foreach (var ownedEntity in ownedEntities)
|
|
{
|
|
Assert.Equal("Date", ownedEntity.GetProperty("Date").GetJsonPropertyName());
|
|
Assert.Equal("Fraction", ownedEntity.GetProperty("Fraction").GetJsonPropertyName());
|
|
Assert.Equal("Enum", ownedEntity.GetProperty("Enum").GetJsonPropertyName());
|
|
}
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Json_entity_nested_enums_have_conversions_to_int_by_default_ToJson_first()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<JsonEntityWithNesting>(
|
|
b =>
|
|
{
|
|
b.OwnsOne(
|
|
x => x.OwnedReference1, bb =>
|
|
{
|
|
bb.ToJson();
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
});
|
|
|
|
b.Ignore(x => x.OwnedReference2);
|
|
b.OwnsMany(
|
|
x => x.OwnedCollection1, bb =>
|
|
{
|
|
bb.ToJson();
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
});
|
|
|
|
b.Ignore(x => x.OwnedCollection2);
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var outerOwnedEntities = model.FindEntityTypes(typeof(OwnedEntityExtraLevel));
|
|
Assert.Equal(2, outerOwnedEntities.Count());
|
|
|
|
foreach (var outerOwnedEntity in outerOwnedEntities)
|
|
{
|
|
Assert.True(outerOwnedEntity.IsMappedToJson());
|
|
var myEnum = outerOwnedEntity.GetDeclaredProperties().Where(p => p.ClrType.IsEnum).Single();
|
|
var typeMapping = myEnum.FindRelationalTypeMapping()!;
|
|
Assert.True(typeMapping.Converter is EnumToNumberConverter<MyJsonEnum, int>);
|
|
}
|
|
|
|
var ownedEntities = model.FindEntityTypes(typeof(OwnedEntity));
|
|
Assert.Equal(8, ownedEntities.Count());
|
|
|
|
foreach (var ownedEntity in ownedEntities)
|
|
{
|
|
Assert.True(ownedEntity.IsMappedToJson());
|
|
var myEnum = ownedEntity.GetDeclaredProperties().Where(p => p.ClrType.IsEnum).Single();
|
|
var typeMapping = myEnum.FindRelationalTypeMapping()!;
|
|
Assert.True(typeMapping.Converter is EnumToNumberConverter<MyJsonEnum, int>);
|
|
}
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Json_entity_nested_enums_have_conversions_to_int_by_default_ToJson_last()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<JsonEntityWithNesting>(
|
|
b =>
|
|
{
|
|
b.OwnsOne(
|
|
x => x.OwnedReference1, bb =>
|
|
{
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
bb.ToJson();
|
|
});
|
|
|
|
b.Ignore(x => x.OwnedReference2);
|
|
b.OwnsMany(
|
|
x => x.OwnedCollection1, bb =>
|
|
{
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
bb.ToJson();
|
|
});
|
|
|
|
b.Ignore(x => x.OwnedCollection2);
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var outerOwnedEntities = model.FindEntityTypes(typeof(OwnedEntityExtraLevel));
|
|
Assert.Equal(2, outerOwnedEntities.Count());
|
|
|
|
foreach (var outerOwnedEntity in outerOwnedEntities)
|
|
{
|
|
Assert.True(outerOwnedEntity.IsMappedToJson());
|
|
var myEnum = outerOwnedEntity.GetDeclaredProperties().Where(p => p.ClrType.IsEnum).Single();
|
|
var typeMapping = myEnum.FindRelationalTypeMapping()!;
|
|
Assert.True(typeMapping.Converter is EnumToNumberConverter<MyJsonEnum, int>);
|
|
}
|
|
|
|
var ownedEntities = model.FindEntityTypes(typeof(OwnedEntity));
|
|
Assert.Equal(8, ownedEntities.Count());
|
|
|
|
foreach (var ownedEntity in ownedEntities)
|
|
{
|
|
Assert.True(ownedEntity.IsMappedToJson());
|
|
var myEnum = ownedEntity.GetDeclaredProperties().Where(p => p.ClrType.IsEnum).Single();
|
|
var typeMapping = myEnum.FindRelationalTypeMapping()!;
|
|
Assert.True(typeMapping.Converter is EnumToNumberConverter<MyJsonEnum, int>);
|
|
}
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Entity_mapped_to_json_and_unwound_afterwards_properly_cleans_up_its_state()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<JsonEntityWithNesting>(
|
|
b =>
|
|
{
|
|
b.OwnsOne(
|
|
x => x.OwnedReference1, bb =>
|
|
{
|
|
bb.ToJson();
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
bb.ToJson(null);
|
|
});
|
|
|
|
b.Ignore(x => x.OwnedReference2);
|
|
b.OwnsMany(
|
|
x => x.OwnedCollection1, bb =>
|
|
{
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
bb.ToJson();
|
|
bb.ToJson(null);
|
|
});
|
|
|
|
b.Ignore(x => x.OwnedCollection2);
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var outerOwnedEntities = model.FindEntityTypes(typeof(OwnedEntityExtraLevel));
|
|
Assert.Equal(2, outerOwnedEntities.Count());
|
|
|
|
foreach (var outerOwnedEntity in outerOwnedEntities)
|
|
{
|
|
Assert.False(outerOwnedEntity.IsMappedToJson());
|
|
#pragma warning disable CS0618
|
|
Assert.Null(outerOwnedEntity.GetContainerColumnTypeMapping());
|
|
#pragma warning restore CS0618
|
|
var myEnum = outerOwnedEntity.GetDeclaredProperties().Where(p => p.ClrType.IsEnum).Single();
|
|
var typeMapping = myEnum.FindRelationalTypeMapping()!;
|
|
|
|
Assert.True(typeMapping.Converter is EnumToNumberConverter<MyJsonEnum, int>);
|
|
}
|
|
|
|
var ownedEntities = model.FindEntityTypes(typeof(OwnedEntity));
|
|
Assert.Equal(8, ownedEntities.Count());
|
|
|
|
foreach (var ownedEntity in ownedEntities)
|
|
{
|
|
Assert.False(ownedEntity.IsMappedToJson());
|
|
#pragma warning disable CS0618
|
|
Assert.Null(ownedEntity.GetContainerColumnTypeMapping());
|
|
#pragma warning restore CS0618
|
|
var myEnum = ownedEntity.GetDeclaredProperties().Where(p => p.ClrType.IsEnum).Single();
|
|
var typeMapping = myEnum.FindRelationalTypeMapping()!;
|
|
Assert.True(typeMapping.Converter is EnumToNumberConverter<MyJsonEnum, int>);
|
|
}
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Json_entity_mapped_to_view()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<JsonEntity>(
|
|
b =>
|
|
{
|
|
b.ToView("MyView");
|
|
b.OwnsOne(x => x.OwnedReference1, bb => bb.ToJson());
|
|
b.Ignore(x => x.OwnedReference2);
|
|
b.OwnsMany(x => x.OwnedCollection1, bb => bb.ToJson());
|
|
b.Ignore(x => x.OwnedCollection2);
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var owner = model.FindEntityType(typeof(JsonEntity))!;
|
|
Assert.Equal("MyView", owner.GetViewName());
|
|
|
|
var ownedEntities = model.FindEntityTypes(typeof(OwnedEntity));
|
|
Assert.Equal(2, ownedEntities.Count());
|
|
Assert.Equal(2, ownedEntities.Where(e => e.IsMappedToJson()).Count());
|
|
Assert.True(ownedEntities.All(x => x.GetViewName() == "MyView"));
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Json_entity_with_custom_property_names()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<JsonEntityWithNesting>(
|
|
b =>
|
|
{
|
|
b.OwnsOne(
|
|
x => x.OwnedReference1, bb =>
|
|
{
|
|
bb.ToJson();
|
|
bb.Property(x => x.Date).HasJsonPropertyName("OuterDate");
|
|
bb.Property(x => x.Fraction).HasJsonPropertyName("OuterFraction");
|
|
bb.Property(x => x.Enum).HasJsonPropertyName("OuterEnum");
|
|
bb.OwnsOne(
|
|
x => x.Reference1, bbb =>
|
|
{
|
|
bbb.HasJsonPropertyName("RenamedReference1");
|
|
bbb.Property(x => x.Date).HasJsonPropertyName("InnerDate");
|
|
bbb.Property(x => x.Fraction).HasJsonPropertyName("InnerFraction");
|
|
bbb.Property(x => x.Enum).HasJsonPropertyName("InnerEnum");
|
|
});
|
|
bb.OwnsOne(
|
|
x => x.Reference2, bbb =>
|
|
{
|
|
bbb.HasJsonPropertyName("RenamedReference2");
|
|
bbb.Property(x => x.Date).HasJsonPropertyName("InnerDate");
|
|
bbb.Property(x => x.Fraction).HasJsonPropertyName("InnerFraction");
|
|
bbb.Property(x => x.Enum).HasJsonPropertyName("InnerEnum");
|
|
});
|
|
bb.OwnsMany(
|
|
x => x.Collection1, bbb =>
|
|
{
|
|
bbb.HasJsonPropertyName("RenamedCollection1");
|
|
bbb.Property(x => x.Date).HasJsonPropertyName("InnerDate");
|
|
bbb.Property(x => x.Fraction).HasJsonPropertyName("InnerFraction");
|
|
bbb.Property(x => x.Enum).HasJsonPropertyName("InnerEnum");
|
|
});
|
|
bb.OwnsMany(
|
|
x => x.Collection2, bbb =>
|
|
{
|
|
bbb.HasJsonPropertyName("RenamedCollection2");
|
|
bbb.Property(x => x.Date).HasJsonPropertyName("InnerDate");
|
|
bbb.Property(x => x.Fraction).HasJsonPropertyName("InnerFraction");
|
|
bbb.Property(x => x.Enum).HasJsonPropertyName("InnerEnum");
|
|
});
|
|
});
|
|
|
|
b.OwnsMany(
|
|
x => x.OwnedCollection1, bb =>
|
|
{
|
|
bb.Property(x => x.Date).HasJsonPropertyName("OuterDate");
|
|
bb.Property(x => x.Fraction).HasJsonPropertyName("OuterFraction");
|
|
bb.Property(x => x.Enum).HasJsonPropertyName("OuterEnum");
|
|
bb.OwnsOne(
|
|
x => x.Reference1, bbb =>
|
|
{
|
|
bbb.HasJsonPropertyName("RenamedReference1");
|
|
bbb.Property(x => x.Date).HasJsonPropertyName("InnerDate");
|
|
bbb.Property(x => x.Fraction).HasJsonPropertyName("InnerFraction");
|
|
bbb.Property(x => x.Enum).HasJsonPropertyName("InnerEnum");
|
|
});
|
|
bb.OwnsOne(
|
|
x => x.Reference2, bbb =>
|
|
{
|
|
bbb.HasJsonPropertyName("RenamedReference2");
|
|
bbb.Property(x => x.Date).HasJsonPropertyName("InnerDate");
|
|
bbb.Property(x => x.Fraction).HasJsonPropertyName("InnerFraction");
|
|
bbb.Property(x => x.Enum).HasJsonPropertyName("InnerEnum");
|
|
});
|
|
bb.OwnsMany(
|
|
x => x.Collection1, bbb =>
|
|
{
|
|
bbb.HasJsonPropertyName("RenamedCollection1");
|
|
bbb.Property(x => x.Date).HasJsonPropertyName("InnerDate");
|
|
bbb.Property(x => x.Fraction).HasJsonPropertyName("InnerFraction");
|
|
bbb.Property(x => x.Enum).HasJsonPropertyName("InnerEnum");
|
|
});
|
|
bb.OwnsMany(
|
|
x => x.Collection2, bbb =>
|
|
{
|
|
bbb.HasJsonPropertyName("RenamedCollection2");
|
|
bbb.Property(x => x.Date).HasJsonPropertyName("InnerDate");
|
|
bbb.Property(x => x.Fraction).HasJsonPropertyName("InnerFraction");
|
|
bbb.Property(x => x.Enum).HasJsonPropertyName("InnerEnum");
|
|
});
|
|
bb.ToJson();
|
|
});
|
|
|
|
b.Ignore(x => x.OwnedReference2);
|
|
b.Ignore(x => x.OwnedCollection2);
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var outerOwnedEntities = model.FindEntityTypes(typeof(OwnedEntityExtraLevel));
|
|
Assert.Equal(2, outerOwnedEntities.Count());
|
|
|
|
foreach (var outerOwnedEntity in outerOwnedEntities)
|
|
{
|
|
Assert.Equal("OuterDate", outerOwnedEntity.GetProperty("Date").GetJsonPropertyName());
|
|
Assert.Equal("OuterFraction", outerOwnedEntity.GetProperty("Fraction").GetJsonPropertyName());
|
|
Assert.Equal("OuterEnum", outerOwnedEntity.GetProperty("Enum").GetJsonPropertyName());
|
|
Assert.Equal(
|
|
"RenamedReference1",
|
|
outerOwnedEntity.GetNavigations().Single(n => n.Name == "Reference1").TargetEntityType.GetJsonPropertyName());
|
|
Assert.Equal(
|
|
"RenamedReference2",
|
|
outerOwnedEntity.GetNavigations().Single(n => n.Name == "Reference2").TargetEntityType.GetJsonPropertyName());
|
|
Assert.Equal(
|
|
"RenamedCollection1",
|
|
outerOwnedEntity.GetNavigations().Single(n => n.Name == "Collection1").TargetEntityType.GetJsonPropertyName());
|
|
Assert.Equal(
|
|
"RenamedCollection2",
|
|
outerOwnedEntity.GetNavigations().Single(n => n.Name == "Collection2").TargetEntityType.GetJsonPropertyName());
|
|
}
|
|
|
|
var ownedEntities = model.FindEntityTypes(typeof(OwnedEntity));
|
|
Assert.Equal(8, ownedEntities.Count());
|
|
|
|
foreach (var ownedEntity in ownedEntities)
|
|
{
|
|
Assert.Equal("InnerDate", ownedEntity.GetProperty("Date").GetJsonPropertyName());
|
|
Assert.Equal("InnerFraction", ownedEntity.GetProperty("Fraction").GetJsonPropertyName());
|
|
Assert.Equal("InnerEnum", ownedEntity.GetProperty("Enum").GetJsonPropertyName());
|
|
}
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Json_entity_and_normal_owned_can_exist_side_to_side_on_same_entity()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
|
|
modelBuilder.Entity<JsonEntity>(
|
|
b =>
|
|
{
|
|
b.OwnsOne(x => x.OwnedReference1);
|
|
b.OwnsOne(x => x.OwnedReference2, bb => bb.ToJson("reference"));
|
|
b.OwnsMany(x => x.OwnedCollection1);
|
|
b.OwnsMany(x => x.OwnedCollection2, bb => bb.ToJson("collection"));
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
|
|
var ownedEntities = model.FindEntityTypes(typeof(OwnedEntity));
|
|
Assert.Equal(4, ownedEntities.Count());
|
|
Assert.Equal(2, ownedEntities.Where(e => e.IsMappedToJson()).Count());
|
|
Assert.Equal(2, ownedEntities.Where(e => e.IsOwned() && !e.IsMappedToJson()).Count());
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public virtual void Json_entity_with_nested_structure_same_property_names_()
|
|
{
|
|
var modelBuilder = CreateModelBuilder();
|
|
modelBuilder.Entity<JsonEntityWithNesting>(
|
|
b =>
|
|
{
|
|
b.OwnsOne(
|
|
x => x.OwnedReference1, bb =>
|
|
{
|
|
bb.ToJson("ref1");
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
});
|
|
|
|
b.OwnsOne(
|
|
x => x.OwnedReference2, bb =>
|
|
{
|
|
bb.ToJson("ref2");
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
});
|
|
|
|
b.OwnsMany(
|
|
x => x.OwnedCollection1, bb =>
|
|
{
|
|
bb.ToJson("col1");
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
});
|
|
|
|
b.OwnsMany(
|
|
x => x.OwnedCollection2, bb =>
|
|
{
|
|
bb.ToJson("col2");
|
|
bb.OwnsOne(x => x.Reference1);
|
|
bb.OwnsOne(x => x.Reference2);
|
|
bb.OwnsMany(x => x.Collection1);
|
|
bb.OwnsMany(x => x.Collection2);
|
|
});
|
|
});
|
|
|
|
var model = modelBuilder.FinalizeModel();
|
|
var outerOwnedEntities = model.FindEntityTypes(typeof(OwnedEntityExtraLevel));
|
|
Assert.Equal(4, outerOwnedEntities.Count());
|
|
|
|
var ownedEntities = model.FindEntityTypes(typeof(OwnedEntity));
|
|
Assert.Equal(16, ownedEntities.Count());
|
|
}
|
|
}
|
|
|
|
public class JetModelBuilderFixture : RelationalModelBuilderFixture
|
|
{
|
|
public override TestHelpers TestHelpers => JetTestHelpers.Instance;
|
|
}
|
|
}
|