// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. namespace FunctionalTests { using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity; using System.Data.Entity.Core; using System.Data.Entity.Core.Metadata.Edm; using System.Data.Entity.ModelConfiguration; using System.Linq; using FunctionalTests.Model; using Xunit; public class PropertyConfigurationScenarioTests : TestBase { [Fact] public void Binary_fixed_length_properties_get_correct_length_in_store() { var modelBuilder = new DbModelBuilder(); modelBuilder.Entity().Property(p => p.Prop_binary_10).IsFixedLength(); modelBuilder.Entity().Property(p => p.NProp_binary_10).IsFixedLength(); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert(p => p.Prop_binary_10).DbEqual(128, f => f.MaxLength); databaseMapping.Assert(p => p.Prop_binary_10).DbEqual(false, f => f.IsMaxLength); databaseMapping.Assert(p => p.NProp_binary_10).DbEqual(128, f => f.MaxLength); databaseMapping.Assert(p => p.NProp_binary_10).DbEqual(false, f => f.IsMaxLength); } [Fact] public void Decimal_property_gets_default_precision_by_convention() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder.Entity(); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.Assert(b => b.PerAssemblyQty).FacetEqual((byte)18, f => f.Precision); databaseMapping.Assert(b => b.PerAssemblyQty).FacetEqual((byte)2, f => f.Scale); } [Fact] public void Duplicate_property_names_differing_by_case_are_uniquified() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder.Entity(); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.Assert().HasColumns("Id", "name", "NAME"); } [Fact] public void Configure_is_max_length_on_property() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder.Entity().Property(c => c.CustomerType).IsMaxLength(); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.Assert(c => c.CustomerType).FacetEqual(true, f => f.IsMaxLength); } private void Configure_is_max_length_on_complex_property(Action configure) { var modelBuilder = new AdventureWorksModelBuilder(); configure(modelBuilder); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert(u => u.Name).FacetEqual(true, c => c.IsMaxLength); // Should be null for nvarchar(max) databaseMapping.Assert("BillOfMaterials").Column("UnitMeasure_Name") .DbEqual(false, c => c.IsMaxLength); databaseMapping.Assert(u => u.Name).FacetEqual(null, c => c.MaxLength); databaseMapping.Assert("BillOfMaterials").Column("UnitMeasure_Name") .DbEqual(null, c => c.MaxLength); databaseMapping.Assert(u => u.Name).FacetEqual(false, c => c.IsFixedLength); databaseMapping.Assert("BillOfMaterials").Column("UnitMeasure_Name") .DbEqual(null, c => c.IsFixedLength); } [Fact] public void Configure_is_max_length_on_complex_property_using_api() { Configure_is_max_length_on_complex_property( modelBuilder => { modelBuilder.Entity().Ignore(b => b.Product); modelBuilder.Entity().Ignore( b => b.Product1); modelBuilder.ComplexType().Property(u => u.Name) .IsMaxLength(); }); } [Fact] public void Configure_is_max_length_on_complex_property_using_configuration() { Configure_is_max_length_on_complex_property( modelBuilder => { var configuration = new ComplexTypeConfiguration(); configuration.Property(u => u.Name).IsMaxLength(); modelBuilder.Configurations.Add(configuration); modelBuilder.Entity().Ignore(b => b.Product); modelBuilder.Entity().Ignore( b => b.Product1); }); } [Fact] public void Configure_has_max_length_on_property() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder.Entity().Property(c => c.CustomerType).HasMaxLength(40); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert(c => c.CustomerType).FacetEqual(40, f => f.MaxLength); } [Fact] public void Configure_store_type_on_property() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder.Entity().Property(c => c.CustomerType).HasColumnType("ntext"); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert(c => c.CustomerType).DbEqual("ntext", f => f.TypeName); } [Fact] public void Configure_nullable_scalar_key() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder.Entity(); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert(l => l.LocationID).IsFalse(t => t.Nullable); } [Fact] public void Overridden_nullable_scalar_key_becomes_nullable_scalar_property() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder .Entity() .HasKey(l => l.Name); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert(l => l.LocationID).IsTrue(t => t.Nullable); } [Fact] public void Configure_identity_on_nullable_scalar_property() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder .Entity() .Property(s => s.MaxQty) .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert(s => s.MaxQty) .MetadataPropertyEqual("Identity", "StoreGeneratedPattern"); databaseMapping.Assert(s => s.MaxQty).DbIsFalse(t => t.Nullable); } [Fact] public void Configure_IsConcurrencyToken_using_api() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder.Entity().Ignore(b => b.Product); modelBuilder.Entity().Ignore(b => b.Product1); modelBuilder.ComplexType().Property(u => u.UnitMeasureCode).IsConcurrencyToken(); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); Assert.Equal( ConcurrencyMode.Fixed, databaseMapping.Model.ComplexTypes.Single() .Properties.Single(p => p.Name == "UnitMeasureCode").ConcurrencyMode); } [Fact] public void Configure_IsConcurrencyToken_using_configuration() { var modelBuilder = new AdventureWorksModelBuilder(); var configuration = new ComplexTypeConfiguration(); configuration.Property(u => u.UnitMeasureCode).IsConcurrencyToken(); modelBuilder.Configurations.Add(configuration); modelBuilder.Entity().Ignore(b => b.Product); modelBuilder.Entity().Ignore(b => b.Product1); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); Assert.Equal( ConcurrencyMode.Fixed, databaseMapping.Model.ComplexTypes.Single() .Properties.Single(p => p.Name == "UnitMeasureCode").ConcurrencyMode); } [Fact] public void Configure_nullable_scalar_property_as_required_using_annotation() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder.Entity(); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.Assert(p => p.SellEndDate).IsFalse(t => t.Nullable); } [Fact] public void Configure_nullable_scalar_property_as_required_using_api() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder.Entity().Property(p => p.ProductSubcategoryID).IsRequired(); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.Assert(p => p.ProductSubcategoryID).IsFalse(t => t.Nullable); } [Fact] public void Configure_identity_on_non_key_property() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder .Entity() .Property(w => w.OrderQty) .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.Assert(w => w.OrderQty) .MetadataPropertyEqual("Identity", "StoreGeneratedPattern"); databaseMapping.Assert(w => w.WorkOrderID) .AnnotationNull("StoreGeneratedPattern"); } [Fact] public void Configure_identity_on_complex_property() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder .ComplexType() .Property(w => w.OrderQty) .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); var databaseMapping = BuildMapping(modelBuilder); Assert.Equal( "Identity", databaseMapping.Model .ComplexTypes.Single() .Properties.Single(p => p.Name == "OrderQty") .MetadataProperties.Single(a => a.Name.EndsWith("StoreGeneratedPattern")).Value); } [Fact] public void Configure_IsRequired_on_a_complex_child_property() { var modelBuilder = new DbModelBuilder(); modelBuilder.Entity() .Property(a => a.HomeAddress.Line1) .IsOptional(); modelBuilder.Entity() .Property(a => a.HomeAddress.Line1) .IsRequired(); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert("CTEmployees") .Column("HomeAddress_Line1") .DbEqual(false, l => l.Nullable); } [Fact] public void Configure_IsRequired_on_a_complex_child_property_conflicting_values() { var modelBuilder = new DbModelBuilder(); modelBuilder.Entity() .Property(a => a.HomeAddress.Line1) .IsRequired(); modelBuilder.Entity() .Property(b => b.Address.Line1) .IsOptional(); Assert.Throws( () => BuildMapping(modelBuilder)); } [Fact] public void Configure_IsOptional_on_a_complex_child_property_after_IsRequired_on_complex_type() { var modelBuilder = new DbModelBuilder(); modelBuilder.ComplexType
().Property(a => a.Line1).IsRequired(); modelBuilder.Entity() .Property(b => b.Address.Line1) .IsOptional(); Assert.Throws( () => BuildMapping(modelBuilder)); } [Fact] public void Configure_IsOptional_and_HasMaxLength_on_a_complex_child_property_after_HasMaxLength_on_complex_type() { var modelBuilder = new DbModelBuilder(); modelBuilder.ComplexType
().Property(a => a.Line1).HasMaxLength(10); modelBuilder.Entity() .Property(a => a.HomeAddress.Line1) .HasMaxLength(20); modelBuilder.Entity() .Property(b => b.Address.Line1) .IsOptional(); Assert.Throws( () => BuildMapping(modelBuilder)); } [Fact] public void Configure_HasColumnName_using_api() { var modelBuilder = new AdventureWorksModelBuilder(); modelBuilder.Entity().HasKey(u => u.UnitMeasureCode); modelBuilder.Entity().Property(u => u.UnitMeasureCode).HasColumnName("Code"); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert("UnitMeasures").HasColumns("Code", "Name"); } [Fact] public void Configure_HasColumnName_using_configuration() { var modelBuilder = new AdventureWorksModelBuilder(); var configuration = new EntityTypeConfiguration(); configuration.HasKey(u => u.UnitMeasureCode); configuration.Property(u => u.UnitMeasureCode).HasColumnName("Code"); modelBuilder.Configurations.Add(configuration); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert("UnitMeasures").HasColumns("Code", "Name"); } [Fact] public void Configure_HasColumnName_using_configuration_can_be_overriden_using_api() { var modelBuilder = new AdventureWorksModelBuilder(); var configuration = new EntityTypeConfiguration(); configuration.HasKey(u => u.UnitMeasureCode); configuration.Property(u => u.UnitMeasureCode).HasColumnName("Code"); modelBuilder.Configurations.Add(configuration); modelBuilder.Entity().Property(u => u.UnitMeasureCode).HasColumnName("UnitCode"); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert("UnitMeasures").HasColumns("UnitCode", "Name"); } [Fact] public void Configure_HasColumnName_on_a_complex_child_property_different_entities() { var modelBuilder = new DbModelBuilder(); modelBuilder.Entity() .Property(a => a.HomeAddress.Line1) .HasColumnName("HomeAddress"); modelBuilder.Entity() .Property(b => b.Address.Line1) .HasColumnName("StreetAddress"); modelBuilder.ComplexType
().Property(a => a.Line1).HasColumnName("FirstLine"); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert("CTEmployees").HasColumns( "CTEmployeeId", "HomeAddress", "HomeAddress_Line2", "FirstLine", "WorkAddress_Line2", "Discriminator"); databaseMapping.Assert("Buildings").HasColumns("Id", "StreetAddress", "Address_Line2"); } [Fact] public void Configure_HasColumnName_on_a_complex_child_property_after_HasColumnName_on_complex_type() { var modelBuilder = new DbModelBuilder(); modelBuilder.ComplexType
().Property(a => a.Line1).HasColumnName("FirstLine"); modelBuilder.Entity(); modelBuilder.Entity() .Property(a => a.HomeAddress.Line1) .HasColumnName("HomeAddress"); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert("CTEmployees").HasColumns( "CTEmployeeId", "HomeAddress", "HomeAddress_Line2", "FirstLine", "WorkAddress_Line2", "Discriminator"); databaseMapping.Assert("Buildings").HasColumns("Id", "FirstLine", "Address_Line2"); } [Fact] public void Configure_HasColumnName_on_complex_type_appearing_several_times_on_an_entity_throws() { var modelBuilder = new DbModelBuilder(); modelBuilder.ComplexType
().Property(a => a.Line1).HasColumnName("FirstLine"); modelBuilder.Entity() .HasKey(e => e.CTEmployeeId); Assert.Throws(() => BuildMapping(modelBuilder)); } [Fact] public void Two_properties_that_both_match_the_primary_key_convention_can_be_disambiguated_using_the_fluent_API() { var modelBuilder = new DbModelBuilder(); modelBuilder.Entity() .HasKey(e => e.ID); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert(e => e.ID) .DbEqual(true, c => c.IsPrimaryKeyColumn); } [Fact] public void Two_properties_that_both_match_the_primary_key_convention_can_be_disambiguated_using_a_data_annotation() { var modelBuilder = new DbModelBuilder(); modelBuilder.Entity(); var databaseMapping = BuildMapping(modelBuilder); databaseMapping.AssertValid(); databaseMapping.Assert(e => e.ID) .DbEqual(true, c => c.IsPrimaryKeyColumn); } } #region Fixtures public class DuplicatePropNames { public int Id { get; set; } public string name { get; set; } public string NAME { get; set; } } public class AllBinaryDataTypes { public int ID { get; set; } public byte[] Prop_binary_10 { get; set; } public byte[] NProp_binary_10 { get; set; } } #endregion public class TwoManyKeys { public int Id { get; set; } public int ID { get; set; } } public class TwoManyKeysWithAnnotation { public int Id { get; set; } [Key] public int ID { get; set; } } }