Skip to content

Commit

Permalink
Add public APIs to configure shared type entities
Browse files Browse the repository at this point in the history
Resolves #9914
  • Loading branch information
smitpatel committed Jul 16, 2020
1 parent c97657e commit ca78f06
Show file tree
Hide file tree
Showing 28 changed files with 875 additions and 116 deletions.
10 changes: 10 additions & 0 deletions src/EFCore/Extensions/MutableModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,16 @@ public static string RemoveOwned([NotNull] this IMutableModel model, [NotNull] T
=> Check.NotNull((Model)model, nameof(model)).RemoveOwned(
Check.NotNull(clrType, nameof(clrType)));

/// <summary>
/// Marks the given entity type as shared, indicating that when discovered matching entity types
/// should be configured as shared type entity type.
/// </summary>
/// <param name="model"> The model to add the owned type to. </param>
/// <param name="clrType"> The type of the entity type that should be owned. </param>
public static void AddShared([NotNull] this IMutableModel model, [NotNull] Type clrType)
=> Check.NotNull((Model)model, nameof(model)).AddShared(
Check.NotNull(clrType, nameof(clrType)), ConfigurationSource.Explicit);

/// <summary>
/// Forces post-processing on the model such that it is ready for use by the runtime. This post
/// processing happens automatically when using <see cref="DbContext.OnModelCreating" />; this method allows it to be run
Expand Down
8 changes: 4 additions & 4 deletions src/EFCore/Metadata/Builders/EntityTypeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ public virtual EntityTypeBuilder OwnsOne(
Check.NotEmpty(navigationName, nameof(navigationName));
Check.NotNull(buildAction, nameof(buildAction));

buildAction.Invoke(OwnsOneBuilder(new TypeIdentity(ownedTypeName), navigationName));
buildAction(OwnsOneBuilder(new TypeIdentity(ownedTypeName), navigationName));
return this;
}

Expand Down Expand Up @@ -412,7 +412,7 @@ public virtual EntityTypeBuilder OwnsOne(
Check.NotEmpty(navigationName, nameof(navigationName));
Check.NotNull(buildAction, nameof(buildAction));

buildAction.Invoke(OwnsOneBuilder(new TypeIdentity(ownedType, (Model)Metadata.Model), navigationName));
buildAction(OwnsOneBuilder(new TypeIdentity(ownedType, (Model)Metadata.Model), navigationName));
return this;
}

Expand Down Expand Up @@ -523,7 +523,7 @@ public virtual EntityTypeBuilder OwnsMany(
Check.NotEmpty(navigationName, nameof(navigationName));
Check.NotNull(buildAction, nameof(buildAction));

buildAction.Invoke(OwnsManyBuilder(new TypeIdentity(ownedTypeName), navigationName));
buildAction(OwnsManyBuilder(new TypeIdentity(ownedTypeName), navigationName));
return this;
}

Expand Down Expand Up @@ -559,7 +559,7 @@ public virtual EntityTypeBuilder OwnsMany(
Check.NotEmpty(navigationName, nameof(navigationName));
Check.NotNull(buildAction, nameof(buildAction));

buildAction.Invoke(OwnsManyBuilder(new TypeIdentity(ownedType, (Model)Metadata.Model), navigationName));
buildAction(OwnsManyBuilder(new TypeIdentity(ownedType, (Model)Metadata.Model), navigationName));
return this;
}

Expand Down
26 changes: 11 additions & 15 deletions src/EFCore/Metadata/Builders/EntityTypeBuilder`.cs
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,7 @@ public virtual OwnedNavigationBuilder<TEntity, TRelatedEntity> OwnsOne<TRelatedE
public virtual OwnedNavigationBuilder<TEntity, TRelatedEntity> OwnsOne<TRelatedEntity>(
[NotNull] Expression<Func<TEntity, TRelatedEntity>> navigationExpression)
where TRelatedEntity : class
=> OwnsOneBuilder<TRelatedEntity>(
new MemberIdentity(Check.NotNull(navigationExpression, nameof(navigationExpression)).GetMemberAccess()));
=> OwnsOneBuilder<TRelatedEntity>(new MemberIdentity(Check.NotNull(navigationExpression, nameof(navigationExpression)).GetMemberAccess()));

/// <summary>
/// <para>
Expand Down Expand Up @@ -380,7 +379,7 @@ public virtual EntityTypeBuilder<TEntity> OwnsOne<TRelatedEntity>(
Check.NotNull(navigationName, nameof(navigationName));
Check.NotNull(buildAction, nameof(buildAction));

buildAction.Invoke(OwnsOneBuilder<TRelatedEntity>(new MemberIdentity(navigationName)));
buildAction(OwnsOneBuilder<TRelatedEntity>(new MemberIdentity(navigationName)));
return this;
}

Expand Down Expand Up @@ -416,7 +415,7 @@ public virtual EntityTypeBuilder<TEntity> OwnsOne<TRelatedEntity>(
Check.NotNull(navigationExpression, nameof(navigationExpression));
Check.NotNull(buildAction, nameof(buildAction));

buildAction.Invoke(OwnsOneBuilder<TRelatedEntity>(new MemberIdentity(navigationExpression.GetMemberAccess())));
buildAction(OwnsOneBuilder<TRelatedEntity>(new MemberIdentity(navigationExpression.GetMemberAccess())));
return this;
}

Expand All @@ -426,9 +425,8 @@ private OwnedNavigationBuilder<TEntity, TRelatedEntity> OwnsOneBuilder<TRelatedE
InternalForeignKeyBuilder relationship;
using (var batch = Builder.Metadata.Model.ConventionDispatcher.DelayConventions())
{
relationship = navigation.MemberInfo == null
? Builder.HasOwnership(typeof(TRelatedEntity), navigation.Name, ConfigurationSource.Explicit)
: Builder.HasOwnership(typeof(TRelatedEntity), navigation.MemberInfo, ConfigurationSource.Explicit);
relationship = Builder.HasOwnership(typeof(TRelatedEntity), navigation, ConfigurationSource.Explicit);

relationship.IsUnique(true, ConfigurationSource.Explicit);
relationship = (InternalForeignKeyBuilder)batch.Run(relationship.Metadata).Builder;
}
Expand Down Expand Up @@ -492,8 +490,7 @@ public virtual OwnedNavigationBuilder<TEntity, TRelatedEntity> OwnsMany<TRelated
public virtual OwnedNavigationBuilder<TEntity, TRelatedEntity> OwnsMany<TRelatedEntity>(
[NotNull] Expression<Func<TEntity, IEnumerable<TRelatedEntity>>> navigationExpression)
where TRelatedEntity : class
=> OwnsManyBuilder<TRelatedEntity>(
new MemberIdentity(Check.NotNull(navigationExpression, nameof(navigationExpression)).GetMemberAccess()));
=> OwnsManyBuilder<TRelatedEntity>(new MemberIdentity(Check.NotNull(navigationExpression, nameof(navigationExpression)).GetMemberAccess()));

/// <summary>
/// <para>
Expand Down Expand Up @@ -523,10 +520,10 @@ public virtual EntityTypeBuilder<TEntity> OwnsMany<TRelatedEntity>(
[NotNull] Action<OwnedNavigationBuilder<TEntity, TRelatedEntity>> buildAction)
where TRelatedEntity : class
{
Check.NotNull(navigationName, nameof(navigationName));
Check.NotEmpty(navigationName, nameof(navigationName));
Check.NotNull(buildAction, nameof(buildAction));

buildAction.Invoke(OwnsManyBuilder<TRelatedEntity>(new MemberIdentity(navigationName)));
buildAction(OwnsManyBuilder<TRelatedEntity>(new MemberIdentity(navigationName)));
return this;
}

Expand Down Expand Up @@ -562,7 +559,7 @@ public virtual EntityTypeBuilder<TEntity> OwnsMany<TRelatedEntity>(
Check.NotNull(navigationExpression, nameof(navigationExpression));
Check.NotNull(buildAction, nameof(buildAction));

buildAction.Invoke(OwnsManyBuilder<TRelatedEntity>(new MemberIdentity(navigationExpression.GetMemberAccess())));
buildAction(OwnsManyBuilder<TRelatedEntity>(new MemberIdentity(navigationExpression.GetMemberAccess())));
return this;
}

Expand All @@ -572,9 +569,8 @@ private OwnedNavigationBuilder<TEntity, TRelatedEntity> OwnsManyBuilder<TRelated
InternalForeignKeyBuilder relationship;
using (var batch = Builder.Metadata.Model.ConventionDispatcher.DelayConventions())
{
relationship = navigation.MemberInfo == null
? Builder.HasOwnership(typeof(TRelatedEntity), navigation.Name, ConfigurationSource.Explicit)
: Builder.HasOwnership(typeof(TRelatedEntity), (PropertyInfo)navigation.MemberInfo, ConfigurationSource.Explicit);
relationship = Builder.HasOwnership(typeof(TRelatedEntity), navigation, ConfigurationSource.Explicit);

relationship.IsUnique(false, ConfigurationSource.Explicit);
relationship = (InternalForeignKeyBuilder)batch.Run(relationship.Metadata).Builder;
}
Expand Down
26 changes: 26 additions & 0 deletions src/EFCore/Metadata/Builders/IConventionModelBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,32 @@ public interface IConventionModelBuilder : IConventionAnnotatableBuilder
/// </returns>
IConventionEntityTypeBuilder Entity([NotNull] string name, bool? shouldBeOwned = false, bool fromDataAnnotation = false);

/// <summary>
/// <para>
/// Returns an object that can be used to configure a given shared type entity type in the model.
/// </para>
/// <para>
/// If an entity type with the provided name is not already part of the model, a new entity type with provided CLR
/// type will be added to the model as shared type entity type.
/// </para>
/// <para>
/// Shared type entity type is an entity type which can share CLR type with other types in the model but has
/// a unique name and always identified by the name.
/// </para>
/// </summary>
/// <param name="name"> The name of the entity type to be configured. </param>
/// <param name="type"> The type of the entity type to be configured. </param>
/// <param name="shouldBeOwned">
/// <see langword="true" /> if the entity type should be owned,
/// <see langword="false" /> if the entity type should not be owned
/// </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns>
/// An object that can be used to configure the entity type if the entity type was added or already part of the model,
/// <see langword="null" /> otherwise.
/// </returns>
IConventionEntityTypeBuilder SharedEntity([NotNull] string name, [NotNull] Type type, bool? shouldBeOwned = false, bool fromDataAnnotation = false);

/// <summary>
/// Returns an object that can be used to configure a given entity type in the model.
/// If an entity type with the provided type is not already part of the model,
Expand Down
13 changes: 13 additions & 0 deletions src/EFCore/Metadata/Builders/IConventionSharedEntityTypeBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// 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.

namespace Microsoft.EntityFrameworkCore.Metadata.Builders
{
/// <summary>
/// This interface is typically used by database providers (and other extensions). It is generally
/// not used in application code.
/// </summary>
public interface IConventionSharedEntityTypeBuilder
{
}
}
8 changes: 4 additions & 4 deletions src/EFCore/Metadata/Builders/OwnedNavigationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ public virtual OwnedNavigationBuilder OwnsOne(

using (DependentEntityType.Model.ConventionDispatcher.DelayConventions())
{
buildAction.Invoke(OwnsOneBuilder(new TypeIdentity(ownedTypeName), navigationName));
buildAction(OwnsOneBuilder(new TypeIdentity(ownedTypeName), navigationName));
return this;
}
}
Expand Down Expand Up @@ -437,7 +437,7 @@ public virtual OwnedNavigationBuilder OwnsOne(

using (DependentEntityType.Model.ConventionDispatcher.DelayConventions())
{
buildAction.Invoke(OwnsOneBuilder(new TypeIdentity(ownedType, (Model)OwnedEntityType.Model), navigationName));
buildAction(OwnsOneBuilder(new TypeIdentity(ownedType, (Model)OwnedEntityType.Model), navigationName));
return this;
}
}
Expand Down Expand Up @@ -551,7 +551,7 @@ public virtual OwnedNavigationBuilder OwnsMany(

using (DependentEntityType.Model.ConventionDispatcher.DelayConventions())
{
buildAction.Invoke(OwnsManyBuilder(new TypeIdentity(ownedTypeName), navigationName));
buildAction(OwnsManyBuilder(new TypeIdentity(ownedTypeName), navigationName));
return this;
}
}
Expand Down Expand Up @@ -590,7 +590,7 @@ public virtual OwnedNavigationBuilder OwnsMany(

using (DependentEntityType.Model.ConventionDispatcher.DelayConventions())
{
buildAction.Invoke(OwnsManyBuilder(new TypeIdentity(ownedType, DependentEntityType.Model), navigationName));
buildAction(OwnsManyBuilder(new TypeIdentity(ownedType, DependentEntityType.Model), navigationName));
return this;
}
}
Expand Down
23 changes: 9 additions & 14 deletions src/EFCore/Metadata/Builders/OwnedNavigationBuilder`.cs
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,7 @@ public virtual OwnedNavigationBuilder<TDependentEntity, TNewDependentEntity> Own
[NotNull] Expression<Func<TDependentEntity, TNewDependentEntity>> navigationExpression)
where TNewDependentEntity : class
=> OwnsOneBuilder<TNewDependentEntity>(
new MemberIdentity(
Check.NotNull(navigationExpression, nameof(navigationExpression)).GetMemberAccess()));
new MemberIdentity(Check.NotNull(navigationExpression, nameof(navigationExpression)).GetMemberAccess()));

/// <summary>
/// <para>
Expand Down Expand Up @@ -319,7 +318,7 @@ public virtual OwnedNavigationBuilder<TEntity, TDependentEntity> OwnsOne<TNewDep
Check.NotNull(navigationName, nameof(navigationName));
Check.NotNull(buildAction, nameof(buildAction));

buildAction.Invoke(OwnsOneBuilder<TNewDependentEntity>(new MemberIdentity(navigationName)));
buildAction(OwnsOneBuilder<TNewDependentEntity>(new MemberIdentity(navigationName)));
return this;
}

Expand Down Expand Up @@ -356,7 +355,7 @@ public virtual OwnedNavigationBuilder<TEntity, TDependentEntity> OwnsOne<TNewDep
Check.NotNull(navigationExpression, nameof(navigationExpression));
Check.NotNull(buildAction, nameof(buildAction));

buildAction.Invoke(OwnsOneBuilder<TNewDependentEntity>(new MemberIdentity(navigationExpression.GetMemberAccess())));
buildAction(OwnsOneBuilder<TNewDependentEntity>(new MemberIdentity(navigationExpression.GetMemberAccess())));
return this;
}

Expand All @@ -367,10 +366,8 @@ private OwnedNavigationBuilder<TDependentEntity, TNewDependentEntity> OwnsOneBui
InternalForeignKeyBuilder relationship;
using (var batch = DependentEntityType.Model.ConventionDispatcher.DelayConventions())
{
relationship = navigation.MemberInfo == null
? DependentEntityType.Builder.HasOwnership(typeof(TNewDependentEntity), navigation.Name, ConfigurationSource.Explicit)
: DependentEntityType.Builder.HasOwnership(
typeof(TNewDependentEntity), (PropertyInfo)navigation.MemberInfo, ConfigurationSource.Explicit);
relationship = DependentEntityType.Builder.HasOwnership(typeof(TNewDependentEntity), navigation, ConfigurationSource.Explicit);

relationship.IsUnique(true, ConfigurationSource.Explicit);
relationship = (InternalForeignKeyBuilder)batch.Run(relationship.Metadata).Builder;
}
Expand Down Expand Up @@ -470,7 +467,7 @@ public virtual OwnedNavigationBuilder<TEntity, TDependentEntity> OwnsMany<TNewDe

using (DependentEntityType.Model.ConventionDispatcher.DelayConventions())
{
buildAction.Invoke(OwnsManyBuilder<TNewDependentEntity>(new MemberIdentity(navigationName)));
buildAction(OwnsManyBuilder<TNewDependentEntity>(new MemberIdentity(navigationName)));
return this;
}
}
Expand Down Expand Up @@ -509,7 +506,7 @@ public virtual OwnedNavigationBuilder<TEntity, TDependentEntity> OwnsMany<TNewDe

using (DependentEntityType.Model.ConventionDispatcher.DelayConventions())
{
buildAction.Invoke(OwnsManyBuilder<TNewDependentEntity>(new MemberIdentity(navigationExpression.GetMemberAccess())));
buildAction(OwnsManyBuilder<TNewDependentEntity>(new MemberIdentity(navigationExpression.GetMemberAccess())));
return this;
}
}
Expand All @@ -520,10 +517,8 @@ private OwnedNavigationBuilder<TDependentEntity, TNewRelatedEntity> OwnsManyBuil
InternalForeignKeyBuilder relationship;
using (var batch = DependentEntityType.Model.ConventionDispatcher.DelayConventions())
{
relationship = navigation.MemberInfo == null
? DependentEntityType.Builder.HasOwnership(typeof(TNewRelatedEntity), navigation.Name, ConfigurationSource.Explicit)
: DependentEntityType.Builder.HasOwnership(
typeof(TNewRelatedEntity), (PropertyInfo)navigation.MemberInfo, ConfigurationSource.Explicit);
relationship = DependentEntityType.Builder.HasOwnership(typeof(TNewRelatedEntity), navigation, ConfigurationSource.Explicit);

relationship.IsUnique(false, ConfigurationSource.Explicit);
relationship = (InternalForeignKeyBuilder)batch.Run(relationship.Metadata).Builder;
}
Expand Down
54 changes: 54 additions & 0 deletions src/EFCore/Metadata/Builders/SharedEntityTypeBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace Microsoft.EntityFrameworkCore.Metadata.Builders
{
/// <summary>
/// <para>
/// Instances of this class are returned from methods when using the <see cref="ModelBuilder" /> API
/// and it is not designed to be directly constructed in your application code.
/// </para>
/// </summary>
public class SharedEntityTypeBuilder
{
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[EntityFrameworkInternal]
public SharedEntityTypeBuilder()
{
}

#region Hidden System.Object members

/// <summary>
/// Returns a string that represents the current object.
/// </summary>
/// <returns> A string that represents the current object. </returns>
[EditorBrowsable(EditorBrowsableState.Never)]
public override string ToString() => base.ToString();

/// <summary>
/// Determines whether the specified object is equal to the current object.
/// </summary>
/// <param name="obj"> The object to compare with the current object. </param>
/// <returns> <see langword="true"/> if the specified object is equal to the current object; otherwise, <see langword="false"/>. </returns>
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj) => base.Equals(obj);

/// <summary>
/// Serves as the default hash function.
/// </summary>
/// <returns> A hash code for the current object. </returns>
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode() => base.GetHashCode();

#endregion
}
}
Loading

0 comments on commit ca78f06

Please sign in to comment.