Skip to content

Commit

Permalink
Add ConventionalAnnotation to store ConfigurationSource in instead of…
Browse files Browse the repository at this point in the history
… InternalMetadataBuilder

Part of #3476
  • Loading branch information
AndriySvyryd committed Oct 30, 2015
1 parent 57dbddb commit 00c71db
Show file tree
Hide file tree
Showing 26 changed files with 244 additions and 204 deletions.
6 changes: 4 additions & 2 deletions src/EntityFramework.Core/EntityFramework.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;CSPROJ</DefineConstants>
<DefineConstants>TRACE;CSPROJ;NET451</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand Down Expand Up @@ -86,6 +86,8 @@
<Compile Include="Internal\IDatabaseProviderSelector.cs" />
<Compile Include="Internal\IndentedStringBuilder.cs" />
<Compile Include="Internal\LazyRef.cs" />
<Compile Include="Metadata\Internal\ConventionalAnnotatable.cs" />
<Compile Include="Metadata\Internal\ConventionalAnnotation.cs" />
<Compile Include="Metadata\Internal\ICanGetNavigations.cs" />
<Compile Include="Metadata\Internal\INavigationAccessors.cs" />
<Compile Include="Metadata\Internal\IPropertyBaseAccessors.cs" />
Expand Down Expand Up @@ -492,4 +494,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>
132 changes: 70 additions & 62 deletions src/EntityFramework.Core/Infrastructure/Annotatable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,143 +3,151 @@

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.Data.Entity.Internal;
using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.Entity.Utilities;

namespace Microsoft.Data.Entity.Infrastructure
{
/// <summary>
/// <para>
/// Base class for types that support reading and writing annotations.
/// Base class for types that support reading and writing annotations.
/// </para>
/// <para>
/// This type is typically used by database providers (and other extensions). It is generally
/// not used in application code.
/// </para>
/// </summary>
public class Annotatable : IAnnotatable
public class Annotatable : IMutableAnnotatable
{
// TODO: Perf: use a mutable structure before the model is made readonly
// Issue #868
private readonly LazyRef<ImmutableSortedSet<Annotation>> _annotations
= new LazyRef<ImmutableSortedSet<Annotation>>(
() => ImmutableSortedSet<Annotation>.Empty.WithComparer(new AnnotationComparer()));
private readonly LazyRef<SortedDictionary<string, Annotation>> _annotations =
new LazyRef<SortedDictionary<string, Annotation>>(() => new SortedDictionary<string, Annotation>());

/// <summary>
/// Gets all annotations on the current object.
/// </summary>
public virtual IEnumerable<Annotation> GetAnnotations() =>
_annotations.HasValue
? _annotations.Value.Values
: Enumerable.Empty<Annotation>();

/// <summary>
/// Adds an annotation to this object. Throws if an annotation with the specified name already exists.
/// </summary>
/// <param name="annotationName"> The key of the annotation to be added. </param>
/// <param name="name"> The key of the annotation to be added. </param>
/// <param name="value"> The value to be stored in the annotation. </param>
/// <returns> The newly added annotation. </returns>
public virtual Annotation AddAnnotation([NotNull] string annotationName, [NotNull] object value)
public virtual Annotation AddAnnotation(string name, object value)
{
Check.NotEmpty(annotationName, nameof(annotationName));
Check.NotEmpty(name, nameof(name));
Check.NotNull(value, nameof(value));

var annotation = new Annotation(annotationName, value);
var annotation = CreateAnnotation(name, value);

return AddAnnotation(name, annotation);
}

protected virtual Annotation AddAnnotation(string name, Annotation annotation)
{
var previousLength = _annotations.Value.Count;
_annotations.Value = _annotations.Value.Add(annotation);
_annotations.Value[name] = annotation;

if (previousLength == _annotations.Value.Count)
{
throw new InvalidOperationException(CoreStrings.DuplicateAnnotation(annotationName));
throw new InvalidOperationException(CoreStrings.DuplicateAnnotation(name));
}

return annotation;
}

/// <summary>
/// Adds an annotation to this object or returns the existing annotation if one with the specified name already exists.
/// Adds an annotation to this object or returns the existing annotation if one with the specified name
/// already exists.
/// </summary>
/// <param name="annotationName"> The key of the annotation to be added. </param>
/// <param name="name"> The key of the annotation to be added. </param>
/// <param name="value"> The value to be stored in the annotation. </param>
/// <returns>
/// The existing annotation if an annotation with the specified name already exists. Otherwise, the newly added annotation.
/// <returns>
/// The existing annotation if an annotation with the specified name already exists. Otherwise, the newly
/// added annotation.
/// </returns>
public virtual Annotation GetOrAddAnnotation([NotNull] string annotationName, [NotNull] object value)
=> FindAnnotation(annotationName) ?? AddAnnotation(annotationName, value);
public virtual Annotation GetOrAddAnnotation([NotNull] string name, [NotNull] object value)
=> FindAnnotation(name) ?? AddAnnotation(name, value);

/// <summary>
/// Gets the annotation with the given name, returning null if it does not exist.
/// </summary>
/// <param name="annotationName"> The key of the annotation to find. </param>
/// <param name="name"> The key of the annotation to find. </param>
/// <returns>
/// The existing annotation if an annotation with the specified name already exists. Otherwise, null.
/// The existing annotation if an annotation with the specified name already exists. Otherwise, null.
/// </returns>
public virtual Annotation FindAnnotation([NotNull] string annotationName)
public virtual Annotation FindAnnotation(string name)
{
Check.NotEmpty(annotationName, nameof(annotationName));
Check.NotEmpty(name, nameof(name));

if (!_annotations.HasValue)
{
return null;
}

Annotation annotation;
return _annotations.HasValue
&& _annotations.Value.TryGetValue(new Annotation(annotationName, "_"), out annotation)
return _annotations.Value.TryGetValue(name, out annotation)
? annotation
: null;
}

/// <summary>
/// Removes the given annotation from this object.
/// </summary>
/// <param name="annotationName"> The annotation to remove. </param>
/// <param name="name"> The annotation to remove. </param>
/// <returns> The annotation that was removed. </returns>
public virtual Annotation RemoveAnnotation([NotNull] string annotationName)
public virtual Annotation RemoveAnnotation(string name)
{
Check.NotNull(annotationName, nameof(annotationName));

var previousAnnotations = _annotations.Value;
var annotation = new Annotation(annotationName, "_");
_annotations.Value = _annotations.Value.Remove(annotation);
Check.NotNull(name, nameof(name));

Annotation removedAnnotations = null;
if (previousAnnotations.Count != _annotations.Value.Count)
var annotation = FindAnnotation(name);
if (annotation == null)
{
previousAnnotations.TryGetValue(annotation, out removedAnnotations);
return null;
}

return removedAnnotations;
_annotations.Value.Remove(name);

return annotation;
}

/// <summary>
/// Gets the value annotation with the given name, returning null if it does not exist.
/// </summary>
/// <param name="annotationName"> The key of the annotation to find. </param>
/// <returns>
/// The value of the existing annotation if an annotation with the specified name already exists. Otherwise, null.
/// <param name="name"> The key of the annotation to find. </param>
/// <returns>
/// The value of the existing annotation if an annotation with the specified name already exists.
/// Otherwise, null.
/// </returns>
// ReSharper disable once AnnotationRedundancyInHierarchy
// TODO: Fix API test to handle indexer
public virtual object this[[NotNull] string annotationName]
public virtual object this[[NotNull] string name]
{
get { return FindAnnotation(annotationName)?.Value; }
get { return FindAnnotation(name)?.Value; }
[param: CanBeNull]
set
{
Check.NotEmpty(annotationName, nameof(annotationName));
Check.NotEmpty(name, nameof(name));

_annotations.Value = _annotations.Value.Remove(new Annotation(annotationName, "_"));

if (value != null)
if (value == null)
{
RemoveAnnotation(name);
}
else
{
AddAnnotation(annotationName, value);
_annotations.Value[name] = CreateAnnotation(name, value);
}
}
}

/// <summary>
/// Gets all annotations on the current object.
/// </summary>
public virtual IEnumerable<Annotation> GetAnnotations()
=> _annotations.HasValue
? (IEnumerable<Annotation>)_annotations.Value
: ImmutableList<Annotation>.Empty;

private class AnnotationComparer : IComparer<IAnnotation>
{
public int Compare(IAnnotation x, IAnnotation y) => StringComparer.Ordinal.Compare(x.Name, y.Name);
}
protected virtual Annotation CreateAnnotation([NotNull] string name, [NotNull] object value)
=> new Annotation(name, value);

/// <summary>
/// Gets all annotations on the current object.
Expand All @@ -149,10 +157,10 @@ private class AnnotationComparer : IComparer<IAnnotation>
/// <summary>
/// Gets the annotation with the given name, returning null if it does not exist.
/// </summary>
/// <param name="annotationName"> The key of the annotation to find. </param>
/// <param name="name"> The key of the annotation to find. </param>
/// <returns>
/// The existing annotation if an annotation with the specified name already exists. Otherwise, null.
/// The existing annotation if an annotation with the specified name already exists. Otherwise, null.
/// </returns>
IAnnotation IAnnotatable.FindAnnotation(string annotationName) => FindAnnotation(annotationName);
IAnnotation IAnnotatable.FindAnnotation(string name) => FindAnnotation(name);
}
}
8 changes: 4 additions & 4 deletions src/EntityFramework.Core/Infrastructure/IAnnotatable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,22 @@ public interface IAnnotatable
/// <summary>
/// Gets the value annotation with the given name, returning null if it does not exist.
/// </summary>
/// <param name="annotationName"> The key of the annotation to find. </param>
/// <param name="name"> The key of the annotation to find. </param>
/// <returns>
/// The value of the existing annotation if an annotation with the specified name already exists. Otherwise, null.
/// </returns>
// ReSharper disable once AnnotationRedundancyInHierarchy
// TODO: Fix API test to handle indexer
object this[[NotNull] string annotationName] { get; }
object this[[NotNull] string name] { get; }

/// <summary>
/// Gets the annotation with the given name, returning null if it does not exist.
/// </summary>
/// <param name="annotationName"> The key of the annotation to find. </param>
/// <param name="name"> The key of the annotation to find. </param>
/// <returns>
/// The existing annotation if an annotation with the specified name already exists. Otherwise, null.
/// </returns>
IAnnotation FindAnnotation([NotNull] string annotationName);
IAnnotation FindAnnotation([NotNull] string name);

/// <summary>
/// Gets all annotations on the current object.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public virtual InternalEntityTypeBuilder Apply(InternalEntityTypeBuilder entityT
var directlyDerivedTypes = entityType.Model.GetEntityTypes().Where(t =>
t.BaseType == entityType.BaseType
&& t.HasClrType()
&& FindClosestBaseType(t) == entityType);
&& FindClosestBaseType(t) == entityType)
.ToList();

foreach (var directlyDerivedType in directlyDerivedTypes)
{
Expand Down
13 changes: 8 additions & 5 deletions src/EntityFramework.Core/Metadata/IMutableAnnotatable.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// 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.Collections.Generic;
using JetBrains.Annotations;
using Microsoft.Data.Entity.Infrastructure;
Expand All @@ -6,10 +9,10 @@ namespace Microsoft.Data.Entity.Metadata
{
public interface IMutableAnnotatable : IAnnotatable
{
new object this[[NotNull] string annotationName] { get; [param: CanBeNull] set; }
new object this[[NotNull] string name] { get; [param: CanBeNull] set; }
new IEnumerable<Annotation> GetAnnotations();
Annotation AddAnnotation([NotNull] string annotationName, [NotNull] object value);
new Annotation FindAnnotation([NotNull] string annotationName);
Annotation RemoveAnnotation([NotNull] string annotationName);
Annotation AddAnnotation([NotNull] string name, [NotNull] object value);
new Annotation FindAnnotation([NotNull] string name);
Annotation RemoveAnnotation([NotNull] string name);
}
}
}
5 changes: 4 additions & 1 deletion src/EntityFramework.Core/Metadata/IMutableForeignKey.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// 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.Collections.Generic;
using JetBrains.Annotations;

Expand All @@ -17,4 +20,4 @@ public interface IMutableForeignKey : IForeignKey, IMutableAnnotatable
new bool? IsRequired { get; set; }
new DeleteBehavior? DeleteBehavior { get; set; }
}
}
}
2 changes: 1 addition & 1 deletion src/EntityFramework.Core/Metadata/IMutableModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ public interface IMutableModel : IModel, IMutableAnnotatable
IMutableEntityType AddEntityType([NotNull] string name);
new IMutableEntityType FindEntityType([NotNull] string name);
IMutableEntityType RemoveEntityType([NotNull] string name);
new IReadOnlyList<IMutableEntityType> GetEntityTypes();
new IEnumerable<IMutableEntityType> GetEntityTypes();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// 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.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.Data.Entity.Infrastructure;

namespace Microsoft.Data.Entity.Metadata.Internal
{
public class ConventionalAnnotatable : Annotatable
{
public new virtual IEnumerable<ConventionalAnnotation> GetAnnotations() => base.GetAnnotations().Cast<ConventionalAnnotation>();

public virtual ConventionalAnnotation AddAnnotation(
[NotNull] string name, [NotNull] object value, ConfigurationSource configurationSource)
=> (ConventionalAnnotation)base.AddAnnotation(name, CreateAnnotation(name, value, configurationSource));

public new virtual ConventionalAnnotation AddAnnotation([NotNull] string name, [NotNull] object value)
=> (ConventionalAnnotation)base.AddAnnotation(name, value);

public new virtual ConventionalAnnotation GetOrAddAnnotation([NotNull] string name, [NotNull] object value)
=> (ConventionalAnnotation)base.GetOrAddAnnotation(name, value);

public new virtual ConventionalAnnotation FindAnnotation([NotNull] string name)
=> (ConventionalAnnotation)base.FindAnnotation(name);

public new virtual ConventionalAnnotation RemoveAnnotation([NotNull] string name)
=> (ConventionalAnnotation)base.RemoveAnnotation(name);

private ConventionalAnnotation CreateAnnotation(
string name, object value, ConfigurationSource configurationSource)
=> new ConventionalAnnotation(name, value, configurationSource);

protected override Annotation CreateAnnotation(string name, object value)
=> CreateAnnotation(name, value, ConfigurationSource.Explicit);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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 JetBrains.Annotations;
using Microsoft.Data.Entity.Infrastructure;

namespace Microsoft.Data.Entity.Metadata.Internal
{
public class ConventionalAnnotation : Annotation
{
private ConfigurationSource _configurationSource;

public ConventionalAnnotation([NotNull] string name, [NotNull] object value, ConfigurationSource configurationSource)
: base(name, value)
{
_configurationSource = configurationSource;
}

public ConfigurationSource GetConfigurationSource() => _configurationSource;

public ConfigurationSource UpdateConfigurationSource(ConfigurationSource configurationSource)
=> _configurationSource = _configurationSource.Max(configurationSource);
}
}
Loading

0 comments on commit 00c71db

Please sign in to comment.