Skip to content

Commit

Permalink
Allow to set Property.ClrType
Browse files Browse the repository at this point in the history
Remove ClrType and IsShadowProperty from the Property constructor
Set default ClrType to string and make properties shadow by default
Move CLR type validation to ModelValidator
Make IModel.GetReferencingForeignKeys extension methods and rename to FindReferencingForeignKeys
  • Loading branch information
AndriySvyryd committed Aug 7, 2015
1 parent 4a11781 commit fd1ee9d
Show file tree
Hide file tree
Showing 98 changed files with 1,384 additions and 1,171 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ private void InitialFixup(InternalEntityEntry entry)
}
}

foreach (var foreignKey in _model.GetReferencingForeignKeys(entityType))
foreach (var foreignKey in _model.FindReferencingForeignKeys(entityType))
{
var dependents = entry.StateManager.GetDependents(entry, foreignKey).ToArray();
if (dependents.Length > 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public ModelForeignKeyUndirectedGraphAdapter([NotNull] Model model)

public override IEnumerable<EntityType> GetOutgoingNeighbours(EntityType from)
=> @from.GetForeignKeys().Select(fk => fk.PrincipalEntityType)
.Union(_model.GetReferencingForeignKeys(@from).Select(fk => fk.DeclaringEntityType));
.Union(_model.FindReferencingForeignKeys(@from).Select(fk => fk.DeclaringEntityType));

public override IEnumerable<EntityType> GetIncomingNeighbours(EntityType to)
=> GetOutgoingNeighbours(to);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ public ModelNavigationsGraphAdapter([NotNull] Model model)

public override IEnumerable<EntityType> GetOutgoingNeighbours(EntityType from)
=> @from.GetForeignKeys().Where(fk => fk.DependentToPrincipal != null).Select(fk => fk.PrincipalEntityType)
.Union(_model.GetReferencingForeignKeys(@from).Where(fk => fk.PrincipalToDependent != null).Select(fk => fk.DeclaringEntityType));
.Union(_model.FindReferencingForeignKeys(@from).Where(fk => fk.PrincipalToDependent != null).Select(fk => fk.DeclaringEntityType));

public override IEnumerable<EntityType> GetIncomingNeighbours(EntityType to)
=> to.GetForeignKeys().Where(fk => fk.PrincipalToDependent != null).Select(fk => fk.PrincipalEntityType)
.Union(_model.GetReferencingForeignKeys(to).Where(fk => fk.DependentToPrincipal != null).Select(fk => fk.DeclaringEntityType));
.Union(_model.FindReferencingForeignKeys(to).Where(fk => fk.DependentToPrincipal != null).Select(fk => fk.DeclaringEntityType));
}
}
30 changes: 29 additions & 1 deletion src/EntityFramework.Core/Internal/ModelValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public virtual void Validate(IModel model)
{
EnsureNoShadowEntities(model);
EnsureNoShadowKeys(model);
EnsureClrPropertyTypesMatch(model);
EnsureValidForeignKeyChains(model);
}

Expand All @@ -36,7 +37,7 @@ protected void EnsureNoShadowKeys(IModel model)
if (key.Properties.Any(p => p.IsShadowProperty))
{
string message;
var referencingFk = model.GetReferencingForeignKeys(key).FirstOrDefault();
var referencingFk = model.FindReferencingForeignKeys(key).FirstOrDefault();
if (referencingFk != null)
{
message = Strings.ReferencedShadowKey(
Expand All @@ -60,6 +61,33 @@ protected void EnsureNoShadowKeys(IModel model)
}
}

protected void EnsureClrPropertyTypesMatch(IModel model)
{
foreach (var entityType in model.EntityTypes)
{
foreach (var property in entityType.GetDeclaredProperties())
{
if (property.IsShadowProperty
|| !entityType.HasClrType())
{
continue;
}

var clrProperty = entityType.ClrType.GetPropertiesInHierarchy(property.Name).FirstOrDefault();
if (clrProperty == null)
{
ShowError(Strings.NoClrProperty(property.Name, entityType.Name));
continue;
}

if (property.ClrType != clrProperty.PropertyType)
{
ShowError(Strings.PropertyWrongClrType(property.Name, entityType.Name));
}
}
}
}

protected void EnsureValidForeignKeyChains(IModel model)
{
var verifiedProperties = new Dictionary<IProperty, IProperty>();
Expand Down
25 changes: 14 additions & 11 deletions src/EntityFramework.Core/Metadata/Builders/EntityTypeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Diagnostics;
using JetBrains.Annotations;
using Microsoft.Data.Entity.ChangeTracking;
using Microsoft.Data.Entity.Infrastructure;
Expand Down Expand Up @@ -132,11 +133,7 @@ public virtual KeyBuilder AlternateKey([NotNull] params string[] propertyNames)
/// <param name="propertyName"> The name of the property to be configured. </param>
/// <returns> An object that can be used to configure the property. </returns>
public virtual PropertyBuilder<TProperty> Property<TProperty>([NotNull] string propertyName)
{
Check.NotEmpty(propertyName, nameof(propertyName));

return new PropertyBuilder<TProperty>(Builder.Property(typeof(TProperty), propertyName, ConfigurationSource.Explicit));
}
=> new PropertyBuilder<TProperty>(PropertyBuilder(typeof(TProperty), propertyName));

/// <summary>
/// <para>
Expand All @@ -155,12 +152,7 @@ public virtual PropertyBuilder<TProperty> Property<TProperty>([NotNull] string p
/// <param name="propertyName"> The name of the property to be configured. </param>
/// <returns> An object that can be used to configure the property. </returns>
public virtual PropertyBuilder Property([NotNull] Type propertyType, [NotNull] string propertyName)
{
Check.NotNull(propertyType, nameof(propertyType));
Check.NotEmpty(propertyName, nameof(propertyName));

return new PropertyBuilder(Builder.Property(propertyType, propertyName, ConfigurationSource.Explicit));
}
=> new PropertyBuilder(PropertyBuilder(propertyType, propertyName));

/// <summary>
/// Excludes the given property from the entity type. This method is typically used to remove properties
Expand Down Expand Up @@ -334,5 +326,16 @@ protected virtual InternalRelationshipBuilder CollectionBuilder(EntityType relat
navigationToDependentName: navigationName ?? "",
configurationSource: ConfigurationSource.Explicit,
isUnique: false);

protected virtual InternalPropertyBuilder PropertyBuilder([NotNull] Type propertyType, string propertyName)
{
Check.NotNull(propertyType, nameof(propertyType));
Check.NotEmpty(propertyName, nameof(propertyName));

var builder = Builder.Property(propertyName, ConfigurationSource.Explicit);
var clrTypeSet = builder.ClrType(propertyType, ConfigurationSource.Explicit);
Debug.Assert(clrTypeSet);
return builder;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.ComponentModel.DataAnnotations;
using System.Reflection;
using Microsoft.Data.Entity.Metadata.Internal;
using Microsoft.Data.Entity.Utilities;

namespace Microsoft.Data.Entity.Metadata.Conventions.Internal
{
public class ConcurrencyCheckAttributeConvention : PropertyAttributeConvention<ConcurrencyCheckAttribute>
{
public override InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder, ConcurrencyCheckAttribute attribute)
public override InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder, ConcurrencyCheckAttribute attribute, PropertyInfo clrProperty)
{
Check.NotNull(propertyBuilder, nameof(propertyBuilder));
Check.NotNull(attribute, nameof(attribute));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;
using Microsoft.Data.Entity.Metadata.Internal;
using Microsoft.Data.Entity.Utilities;

namespace Microsoft.Data.Entity.Metadata.Conventions.Internal
{
public class DatabaseGeneratedAttributeConvention : PropertyAttributeConvention<DatabaseGeneratedAttribute>
{
public override InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder, DatabaseGeneratedAttribute attribute)
public override InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder, DatabaseGeneratedAttribute attribute, PropertyInfo clrProperty)
{
Check.NotNull(propertyBuilder, nameof(propertyBuilder));
Check.NotNull(attribute, nameof(attribute));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ public class ForeignKeyPropertyDiscoveryConvention : IForeignKeyConvention
{
public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder)
{
if (relationshipBuilder.Metadata.Properties.All(fk => fk.IsShadowProperty))
var foreignKey = (IForeignKey)relationshipBuilder.Metadata;
if (foreignKey.Properties.All(fk => fk.IsShadowProperty))
{
var foreignKey = relationshipBuilder.Metadata;
var foreignKeyProperties = FindCandidateForeignKeyProperties(relationshipBuilder, onDependent: true);

if (((IForeignKey)foreignKey).IsUnique
if (foreignKey.IsUnique
&& !foreignKey.IsSelfPrimaryKeyReferencing())
{
if (ShouldFlip(relationshipBuilder, foreignKeyProperties))
Expand All @@ -31,7 +31,8 @@ public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder rel

if (foreignKeyProperties == null)
{
foreignKeyProperties = GetCompatiblePrimaryKeyProperties(foreignKey.DeclaringEntityType, foreignKey.PrincipalKey.Properties);
foreignKeyProperties = GetCompatiblePrimaryKeyProperties(
relationshipBuilder.Metadata.DeclaringEntityType, relationshipBuilder.Metadata.PrincipalKey.Properties);
}
}

Expand Down Expand Up @@ -84,9 +85,9 @@ private bool ShouldFlip(InternalRelationshipBuilder relationshipBuilder, IReadOn
var model = foreignKey.DeclaringEntityType.Model;
var principalPk = foreignKey.PrincipalEntityType.FindPrimaryKey();
var principalPkReferenceThreshold = foreignKey.PrincipalKey == principalPk ? 1 : 0;
var isPrincipalKeyReferenced = principalPk != null && model.GetReferencingForeignKeys(principalPk).Count > principalPkReferenceThreshold;
var isPrincipalKeyReferenced = principalPk != null && model.FindReferencingForeignKeys(principalPk).Count() > principalPkReferenceThreshold;
var dependentPk = foreignKey.DeclaringEntityType.FindPrimaryKey();
var isDependentPrimaryKeyReferenced = dependentPk != null && model.GetReferencingForeignKeys(dependentPk).Count > 0;
var isDependentPrimaryKeyReferenced = dependentPk != null && model.FindReferencingForeignKeys(dependentPk).Any();

if (isPrincipalKeyReferenced
&& !isDependentPrimaryKeyReferenced)
Expand Down Expand Up @@ -162,7 +163,7 @@ private IReadOnlyList<Property> FindMatchingNonShadowProperties(InternalRelation
}

var foreignKeyProperties = new List<Property>();
foreach (var referencedProperty in propertiesToReference)
foreach (IProperty referencedProperty in propertiesToReference)
{
var property = TryGetProperty(entityType,
baseName + referencedProperty.Name,
Expand All @@ -179,7 +180,7 @@ private IReadOnlyList<Property> FindMatchingNonShadowProperties(InternalRelation
{
var property = TryGetProperty(entityType,
baseName + "Id",
propertiesToReference.Single().ClrType.UnwrapNullableType());
((IProperty)propertiesToReference.Single()).ClrType.UnwrapNullableType());

if (property != null)
{
Expand Down Expand Up @@ -211,13 +212,14 @@ private IReadOnlyList<Property> FindMatchingNonShadowProperties(InternalRelation

private Property TryGetProperty(EntityType entityType, string name, Type type)
{
foreach (var property in entityType.Properties)
foreach (var mutableProperty in entityType.Properties)
{
var property = (IProperty)mutableProperty;
if (property.Name.Equals(name, StringComparison.OrdinalIgnoreCase)
&& !property.IsShadowProperty
&& property.ClrType.UnwrapNullableType() == type)
{
return property;
return mutableProperty;
}
}
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using Microsoft.Data.Entity.Internal;
using Microsoft.Data.Entity.Metadata.Internal;
using Microsoft.Data.Entity.Utilities;
Expand All @@ -13,7 +14,7 @@ namespace Microsoft.Data.Entity.Metadata.Conventions.Internal
{
public class KeyAttributeConvention : PropertyAttributeConvention<KeyAttribute>, IModelConvention
{
public override InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder, KeyAttribute attribute)
public override InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder, KeyAttribute attribute, PropertyInfo clrProperty)
{
Check.NotNull(propertyBuilder, nameof(propertyBuilder));
Check.NotNull(attribute, nameof(attribute));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,10 @@ protected virtual void SetValueGeneration(
Check.NotNull(properties, nameof(properties));

foreach (var property in properties.Where(
property => property.DeclaringEntityType.FindDeclaredProperty(property.Name) != null
&& !entityTypeBuilder.Metadata.GetForeignKeys().SelectMany(fk => fk.Properties).Contains(property)))
property => !entityTypeBuilder.Metadata.GetForeignKeys().SelectMany(fk => fk.Properties).Contains(property)))
{
entityTypeBuilder.ModelBuilder.Entity(property.DeclaringEntityType.Name, ConfigurationSource.Convention)
.Property(property.ClrType, property.Name, ConfigurationSource.Convention)
.Property(property.Name, ConfigurationSource.Convention)
?.UseValueGenerator(true, ConfigurationSource.Convention);
}
}
Expand All @@ -60,9 +59,9 @@ protected virtual void SetIdentity(

if (entityTypeBuilder.Metadata.FindPrimaryKey(properties) != null)
{
foreach (var property in entityTypeBuilder.Metadata.Properties)
foreach (var property in entityTypeBuilder.Metadata.GetDeclaredProperties())
{
entityTypeBuilder.Property(property.ClrType, property.Name, ConfigurationSource.Convention)
entityTypeBuilder.Property(property.Name, ConfigurationSource.Convention)
?.ValueGenerated(null, ConfigurationSource.Convention);
}

Expand All @@ -71,8 +70,8 @@ protected virtual void SetIdentity(
ValueGeneratedOnAddProperty(properties, entityTypeBuilder.Metadata)) != null)
{
entityTypeBuilder.Property(
valueGeneratedOnAddProperty.ClrType,
valueGeneratedOnAddProperty.Name,
((IProperty)valueGeneratedOnAddProperty).ClrType,
ConfigurationSource.Convention)
?.ValueGenerated(ValueGenerated.OnAdd, ConfigurationSource.Convention);
}
Expand All @@ -86,7 +85,7 @@ public virtual Property ValueGeneratedOnAddProperty(
{
var property = properties.First();

var propertyType = property.ClrType.UnwrapNullableType();
var propertyType = ((IProperty)property).ClrType.UnwrapNullableType();

if ((propertyType.IsInteger()
|| propertyType == typeof(Guid))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.ComponentModel.DataAnnotations;
using System.Reflection;
using Microsoft.Data.Entity.Metadata.Internal;
using Microsoft.Data.Entity.Utilities;

namespace Microsoft.Data.Entity.Metadata.Conventions.Internal
{
public class MaxLengthAttributeConvention : PropertyAttributeConvention<MaxLengthAttribute>
{
public override InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder, MaxLengthAttribute attribute)
public override InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder, MaxLengthAttribute attribute, PropertyInfo clrProperty)
{
Check.NotNull(propertyBuilder, nameof(propertyBuilder));
Check.NotNull(attribute, nameof(attribute));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.ComponentModel.DataAnnotations.Schema;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.ComponentModel.DataAnnotations.Schema;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;
using Microsoft.Data.Entity.Metadata.Internal;
using Microsoft.Data.Entity.Utilities;

namespace Microsoft.Data.Entity.Metadata.Conventions.Internal
{
public class NotMappedPropertyAttributeConvention : PropertyAttributeConvention<NotMappedAttribute>
{
public override InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder, NotMappedAttribute attribute)
public override InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder, NotMappedAttribute attribute, PropertyInfo clrProperty)
{
Check.NotNull(propertyBuilder, nameof(propertyBuilder));
Check.NotNull(attribute, nameof(attribute));
Expand Down
Loading

0 comments on commit fd1ee9d

Please sign in to comment.