Skip to content

Commit

Permalink
Add support for InMemory
Browse files Browse the repository at this point in the history
  • Loading branch information
kmataru authored and bricelam committed Dec 12, 2020
1 parent 7cd8a0e commit 0706c52
Show file tree
Hide file tree
Showing 13 changed files with 590 additions and 0 deletions.
52 changes: 52 additions & 0 deletions EFCore.InMemory.HierarchyId.Test/DatabaseContextTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System.Linq;
using Microsoft.EntityFrameworkCore.SqlServer.Test.Models;
using Xunit;

namespace Microsoft.EntityFrameworkCore.SqlServer
{
public class DatabaseContextTests
{
[Fact]
public void Should_CreateDatabaseContext()
{
// Arrange
var databaseContext = new AbrahamicContext();

// Act
databaseContext.Database.EnsureCreated();

// Assert
Assert.NotNull(databaseContext);
Assert.NotNull(databaseContext.Patriarchy);
Assert.Equal(16, databaseContext.Patriarchy.Count());
}

[Fact]
public void Should_GetEphraimEntryByName()
{
// Arrange
var databaseContext = new AbrahamicContext();

// Act
databaseContext.Database.EnsureCreated();
var ephraim = databaseContext.Patriarchy.Single(w => w.Name == "Ephraim");

// Assert
Assert.Equal(HierarchyId.Parse("/1/1/11.1/"), ephraim.Id);
}

[Fact]
public void Should_GetEphraimEntryById()
{
// Arrange
var databaseContext = new AbrahamicContext();

// Act
databaseContext.Database.EnsureCreated();
var ephraim = databaseContext.Patriarchy.Single(w => w.Id == HierarchyId.Parse("/1/1/11.1/"));

// Assert
Assert.Equal("Ephraim", ephraim.Name);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net5.0;netcoreapp3.1</TargetFrameworks>
<IsPackable>false</IsPackable>
<AssemblyName>EntityFrameworkCore.InMemory.HierarchyId.Test</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore.InMemory</RootNamespace>
<Features>strict</Features>
<LangVersion>latest</LangVersion>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\key.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\EFCore.InMemory.HierarchyId\EFCore.InMemory.HierarchyId.csproj" />
</ItemGroup>

</Project>
34 changes: 34 additions & 0 deletions EFCore.InMemory.HierarchyId.Test/Test/Models/AbrahamicContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
namespace Microsoft.EntityFrameworkCore.SqlServer.Test.Models
{
class AbrahamicContext : DbContext
{
public DbSet<Patriarch> Patriarchy { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options
.UseInMemoryDatabase(
"HierarchyIdTests",
x => x.UseHierarchyId()
);

protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Patriarch>()
.HasData(
new Patriarch { Id = HierarchyId.GetRoot(), Name = "Abraham" },
new Patriarch { Id = HierarchyId.Parse("/1/"), Name = "Isaac" },
new Patriarch { Id = HierarchyId.Parse("/1/1/"), Name = "Jacob" },
new Patriarch { Id = HierarchyId.Parse("/1/1/1/"), Name = "Reuben" },
new Patriarch { Id = HierarchyId.Parse("/1/1/2/"), Name = "Simeon" },
new Patriarch { Id = HierarchyId.Parse("/1/1/3/"), Name = "Levi" },
new Patriarch { Id = HierarchyId.Parse("/1/1/4/"), Name = "Judah" },
new Patriarch { Id = HierarchyId.Parse("/1/1/5/"), Name = "Issachar" },
new Patriarch { Id = HierarchyId.Parse("/1/1/6/"), Name = "Zebulun" },
new Patriarch { Id = HierarchyId.Parse("/1/1/7/"), Name = "Dan" },
new Patriarch { Id = HierarchyId.Parse("/1/1/8/"), Name = "Naphtali" },
new Patriarch { Id = HierarchyId.Parse("/1/1/9/"), Name = "Gad" },
new Patriarch { Id = HierarchyId.Parse("/1/1/10/"), Name = "Asher" },
new Patriarch { Id = HierarchyId.Parse("/1/1/11.1/"), Name = "Ephraim" },
new Patriarch { Id = HierarchyId.Parse("/1/1/11.2/"), Name = "Manasseh" },
new Patriarch { Id = HierarchyId.Parse("/1/1/12/"), Name = "Benjamin" });
}
}
8 changes: 8 additions & 0 deletions EFCore.InMemory.HierarchyId.Test/Test/Models/Patriarch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Microsoft.EntityFrameworkCore.SqlServer.Test.Models
{
class Patriarch
{
public HierarchyId Id { get; set; }
public string Name { get; set; }
}
}
61 changes: 61 additions & 0 deletions EFCore.InMemory.HierarchyId/EFCore.InMemory.HierarchyId.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<AssemblyName>EntityFrameworkCore.InMemory.HierarchyId</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore.InMemory</RootNamespace>
<Authors>Adrian Paul Nutiu</Authors>
<Description>Adds hierarchyid support to the in-memory EF Core provider</Description>
<PackageProjectUrl>https://github.com/efcore/EFCore.SqlServer.HierarchyId</PackageProjectUrl>
<PackageTags>EFCore;InMemory;HierarchyId</PackageTags>
<RepositoryUrl>https://github.com/efcore/EFCore.SqlServer.HierarchyId.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Copyright>© 2020 Brice Lambson, et al. All rights reserved.</Copyright>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\key.snk</AssemblyOriginatorKeyFile>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>2.0.0</Version>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Features>strict</Features>
<LangVersion>latest</LangVersion>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReleaseNotes>https://github.com/efcore/EFCore.SqlServer.HierarchyId/releases</PackageReleaseNotes>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\EFCore.SqlServer.HierarchyId.Abstractions\EFCore.SqlServer.HierarchyId.Abstractions.csproj" />
</ItemGroup>

<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>

<Target Name="SetNuspecProperties" BeforeTargets="GenerateNuspec">
<PropertyGroup>
<NuspecProperties>$(NuspecProperties);id=$(PackageId)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);version=$(PackageVersion)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);author=$(Authors)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);description=$(Description)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);copyright=$(Copyright)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);configuration=$(Configuration)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);repositoryUrl=$(RepositoryUrl)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);efcoreVersion=@(PackageReference-&gt;WithMetadataValue('Identity', 'Microsoft.EntityFrameworkCore.SqlServer')-&gt;Metadata('Version'))</NuspecProperties>
</PropertyGroup>
</Target>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.InMemory.Infrastructure;

namespace Microsoft.EntityFrameworkCore
{
/// <summary>
/// HierarchyId specific extension methods for <see cref="InMemoryDbContextOptionsBuilder"/>.
/// </summary>
public static class InMemoryHierarchyIdDbContextOptionsBuilderExtensions
{
/// <summary>
/// Enable HierarchyId mappings.
/// </summary>
/// <param name="optionsBuilder">The builder being used to configure in-memory database.</param>
/// <returns>The options builder so that further configuration can be chained.</returns>
public static InMemoryDbContextOptionsBuilder UseHierarchyId(
this InMemoryDbContextOptionsBuilder optionsBuilder)
{
var optionsBuilderPropertyInfo = optionsBuilder.GetType().GetProperty("OptionsBuilder", BindingFlags.Instance | BindingFlags.NonPublic);
var coreOptionsBuilder = optionsBuilderPropertyInfo.GetValue(optionsBuilder) as DbContextOptionsBuilder;

var extension = coreOptionsBuilder.Options.FindExtension<InMemoryHierarchyIdOptionsExtension>()
?? new InMemoryHierarchyIdOptionsExtension();

((IDbContextOptionsBuilderInfrastructure)coreOptionsBuilder).AddOrUpdateExtension(extension);

return optionsBuilder;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.InMemory.Storage;
using Microsoft.EntityFrameworkCore.Storage;

namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// EntityFrameworkCore.SqlServer.HierarchyId extension methods for <see cref="IServiceCollection"/>.
/// </summary>
public static class InMemoryHierarchyIdServiceCollectionExtensions
{
/// <summary>
/// Adds the services required for HierarchyId support in the SQL Server provider for Entity Framework.
/// </summary>
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to add services to.</param>
/// <returns>The same service collection so that multiple calls can be chained.</returns>
public static IServiceCollection AddEntityFrameworkInMemoryHierarchyId(
this IServiceCollection serviceCollection)
{
new EntityFrameworkServicesBuilder(serviceCollection)
.TryAddProviderSpecificServices(
x => x
.TryAddSingletonEnumerable<ITypeMappingSourcePlugin, InMemoryHierarchyIdTypeMappingSourcePlugin>()
);

return serviceCollection;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.InMemory.Properties;
using Microsoft.EntityFrameworkCore.InMemory.Storage;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.EntityFrameworkCore.InMemory.Infrastructure
{
internal class InMemoryHierarchyIdOptionsExtension : IDbContextOptionsExtension
{
public DbContextOptionsExtensionInfo info;

public DbContextOptionsExtensionInfo Info => info ??= new ExtensionInfo(this);

public virtual void ApplyServices(IServiceCollection services)
{
services.AddEntityFrameworkInMemoryHierarchyId();
}

public virtual void Validate(IDbContextOptions options)
{
var internalServiceProvider = options.FindExtension<CoreOptionsExtension>()?.InternalServiceProvider;
if (internalServiceProvider != null)
{
using (var scope = internalServiceProvider.CreateScope())
{
if (scope.ServiceProvider.GetService<IEnumerable<ITypeMappingSourcePlugin>>()
?.Any(s => s is InMemoryHierarchyIdTypeMappingSourcePlugin) != true)
{
throw new InvalidOperationException(Resources.ServicesMissing);
}
}
}
}

private sealed class ExtensionInfo : DbContextOptionsExtensionInfo
{
public ExtensionInfo(IDbContextOptionsExtension extension)
: base(extension)
{
}

private new InMemoryHierarchyIdOptionsExtension Extension
=> (InMemoryHierarchyIdOptionsExtension)base.Extension;

public override bool IsDatabaseProvider => false;

public override long GetServiceProviderHashCode() => 0;

public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
=> debugInfo["InMemory:" + nameof(InMemoryHierarchyIdDbContextOptionsBuilderExtensions.UseHierarchyId)] = "1";

public override string LogFragment => "using HierarchyId ";
}
}
}
72 changes: 72 additions & 0 deletions EFCore.InMemory.HierarchyId/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 0706c52

Please sign in to comment.