Skip to content

Commit

Permalink
Incremental steps to netnative support
Browse files Browse the repository at this point in the history
  • Loading branch information
Nate McMaster committed Oct 19, 2015
1 parent 00355cc commit 31f6f24
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 28 deletions.
1 change: 1 addition & 0 deletions src/EntityFramework.Core/EntityFramework.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@
<Compile Include="..\Shared\SharedTypeExtensions.cs">
<Link>Extensions\Internal\SharedTypeExtensions.cs</Link>
</Compile>
<Compile Include="Utilities\Imply.cs" />
<Compile Include="ValueGeneration\GuidValueGenerator.cs" />
<Compile Include="ValueGeneration\HiLoValueGeneratorState.cs" />
<Compile Include="ValueGeneration\HiLoValueGenerator.cs" />
Expand Down
16 changes: 4 additions & 12 deletions src/EntityFramework.Core/Metadata/Internal/ClrAccessorSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.Data.Entity.Internal;
Expand All @@ -12,9 +11,6 @@ namespace Microsoft.Data.Entity.Metadata.Internal
public abstract class ClrAccessorSource<TAccessor> : IClrAccessorSource<TAccessor>
where TAccessor : class
{
private static readonly MethodInfo _genericCreate
= typeof(ClrAccessorSource<TAccessor>).GetTypeInfo().GetDeclaredMethods("CreateGeneric").Single();

private readonly ThreadSafeDictionaryCache<Tuple<Type, string>, TAccessor> _cache
= new ThreadSafeDictionaryCache<Tuple<Type, string>, TAccessor>();

Expand All @@ -24,13 +20,9 @@ public virtual TAccessor GetAccessor(IPropertyBase property)
public virtual TAccessor GetAccessor(Type declaringType, string propertyName)
=> _cache.GetOrAdd(Tuple.Create(declaringType, propertyName), k => Create(k.Item1.GetAnyProperty(k.Item2)));

private TAccessor Create(PropertyInfo property)
{
var boundMethod = _genericCreate.MakeGenericMethod(property.DeclaringType, property.PropertyType, property.PropertyType.UnwrapNullableType());

return (TAccessor)boundMethod.Invoke(this, new object[] { property });
}

protected abstract TAccessor CreateGeneric<TEntity, TValue, TNonNullableEnumValue>([NotNull] PropertyInfo property) where TEntity : class;
// TODO revisit when .NET Native supports ImpliesMethodInstantiation
// original version used generics, which is much cleaner and performant but fails after ILC strips reflection info
// https://github.com/aspnet/EntityFramework/issues/3477
protected abstract TAccessor Create([NotNull] PropertyInfo property);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@

using System;
using System.Reflection;
using JetBrains.Annotations;

namespace Microsoft.Data.Entity.Metadata.Internal
{
public class ClrPropertyGetterSource : ClrAccessorSource<IClrPropertyGetter>
{
protected override IClrPropertyGetter CreateGeneric<TEntity, TValue, TNonNullableEnumValue>(PropertyInfo property)
=> new ClrPropertyGetter<TEntity, TValue>(
(Func<TEntity, TValue>)property.GetMethod.CreateDelegate(typeof(Func<TEntity, TValue>)));
protected override IClrPropertyGetter Create([NotNull] PropertyInfo property)
{
var types = new[] { property.DeclaringType, property.PropertyType };
var getterType = typeof(ClrPropertyGetter<,>).MakeGenericType(types);
var funcType = typeof(Func<,>).MakeGenericType(types);
return (IClrPropertyGetter)Activator.CreateInstance(getterType, property.GetMethod.CreateDelegate(funcType));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,32 @@

using System;
using System.Reflection;
using JetBrains.Annotations;

namespace Microsoft.Data.Entity.Metadata.Internal
{
public class ClrPropertySetterSource : ClrAccessorSource<IClrPropertySetter>
{
protected override IClrPropertySetter CreateGeneric<TEntity, TValue, TNonNullableEnumValue>(PropertyInfo property)
protected override IClrPropertySetter Create([NotNull] PropertyInfo property)
{
// TODO: Handle case where there is not setter or setter is private on a base type
// Issue #753
var setterDelegate = (Action<TEntity, TValue>)property.SetMethod.CreateDelegate(typeof(Action<TEntity, TValue>));

return (property.PropertyType.IsNullableType()
&& property.PropertyType.UnwrapNullableType().GetTypeInfo().IsEnum) ?
new NullableEnumClrPropertySetter<TEntity, TValue, TNonNullableEnumValue>(setterDelegate) :
(IClrPropertySetter)new ClrPropertySetter<TEntity, TValue>(setterDelegate);
var types = new[] { property.DeclaringType, property.PropertyType };
var actionType = typeof(Action<,>).MakeGenericType(types);

Type setterType;
if (property.PropertyType.IsNullableType()
&& property.PropertyType.UnwrapNullableType().GetTypeInfo().IsEnum)
{
setterType = typeof(NullableEnumClrPropertySetter<,,>).MakeGenericType(property.DeclaringType, property.PropertyType, property.PropertyType.UnwrapNullableType());
}
else
{
setterType = typeof(ClrPropertySetter<,>).MakeGenericType(types);
}

return (IClrPropertySetter)Activator.CreateInstance(setterType, property.SetMethod.CreateDelegate(actionType));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library>
<Assembly Name="EntityFramework.Core" Activate="All" />
<!-- TODO optimize this for types that actually need reflection -->
<Assembly Name="EntityFramework.Core" Dynamic="Required All" />

<!-- TODO https://github.com/aspnet/EntityFramework/issues/3477 -->
<Type Name="Microsoft.Data.Entity.DbSet{TEntity}">
<GenericParameter Name="TEntity" Dynamic="Required All"/>
<ImpliesType Name="Microsoft.Data.Entity.Utilities.ImpliedEntityType{TEntity}" Dynamic="Required All"/>
</Type>

</Library>
</Directives>
79 changes: 79 additions & 0 deletions src/EntityFramework.Core/Utilities/Imply.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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.

#pragma warning disable 0169

using Microsoft.Data.Entity.Storage;
using System;
using Microsoft.Data.Entity.ChangeTracking.Internal;
using Microsoft.Data.Entity.Metadata.Internal;

namespace Microsoft.Data.Entity.Utilities
{
// This code exists only to trick the ILC compliation to include metadata
// about combinations of entity types and our internal types.
// This is the jumping off point for a reasoning about what generic types
// may exist at runtime.
// https://github.com/aspnet/EntityFramework/issues/3477
internal class ImpliedEntityType<TEntity>
where TEntity : class
{
InternalImplyValuesAndTypes<TEntity> EntityValueProp;

InternalImpliesTypes<TEntity> EntityProp;
InternalImpliesTypes<char> CharProp;
InternalImpliesTypes<short> Int16Prop;
InternalImpliesTypes<ushort> UInt16Prop;
InternalImpliesTypes<int> Int32Prop;
InternalImpliesTypes<uint> UInt32Prop;
InternalImpliesTypes<long> Int64Prop;
InternalImpliesTypes<long> UInt64Prop;
InternalImpliesTypes<double> DoubleProp;
InternalImpliesTypes<decimal> DecimalProp;
InternalImpliesTypes<float> FloatProp;
InternalImpliesTypes<string> StringProp;
InternalImpliesTypes<bool> BoolProp;
InternalImpliesTypes<byte> ByteProp;
InternalImpliesTypes<Guid> GuidProp;
InternalImpliesTypes<TimeSpan> TimeSpanProp;
InternalImpliesTypes<DateTime> DateTimeProp;
InternalImpliesTypes<DateTimeOffset> DateTimeOffsetProp;
}

internal class InternalImpliesTypes<T>
{
void CompileQuery()
=> ((IDatabase)new object()).CompileQuery<T>(null);

SimpleEntityKeyFactory<T> KeyFactoryType;
}

internal class InternalImplyTypes<TSystemType, TUserType>
where TUserType : class
{
ClrPropertyGetter<TUserType, TSystemType> ClrPropertyGetter;
ClrPropertySetter<TUserType, TSystemType> ClrPropertySetter;
}

internal class InternalImplyValuesAndTypes<TEntity>
where TEntity : class
{
InternalImplyTypes<char, TEntity> CharProp;
InternalImplyTypes<short, TEntity> Int16Prop;
InternalImplyTypes<ushort, TEntity> UInt16Prop;
InternalImplyTypes<int, TEntity> Int32Prop;
InternalImplyTypes<uint, TEntity> UInt32Prop;
InternalImplyTypes<long, TEntity> Int64Prop;
InternalImplyTypes<long, TEntity> UInt64Prop;
InternalImplyTypes<double, TEntity> DoubleProp;
InternalImplyTypes<decimal, TEntity> DecimalProp;
InternalImplyTypes<float, TEntity> FloatProp;
InternalImplyTypes<string, TEntity> StringProp;
InternalImplyTypes<bool, TEntity> BoolProp;
InternalImplyTypes<byte, TEntity> ByteProp;
InternalImplyTypes<Guid, TEntity> GuidProp;
InternalImplyTypes<TimeSpan, TEntity> TimeSpanProp;
InternalImplyTypes<DateTime, TEntity> DateTimeProp;
InternalImplyTypes<DateTimeOffset, TEntity> DateTimeOffsetProp;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library>
<Assembly Name="EntityFramework.MicrosoftSqlServer" Dynamic="Required All" />
<!-- TODO optimize this for types that actually need reflection -->
<Assembly Name="EntityFramework.MicrosoftSqlServer" Activate="All" />
</Library>
</Directives>
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,27 @@
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library>
<!-- TODO optimize this for types that actually need reflection -->
<Assembly Name="EntityFramework.Relational" Activate="All" />
<Type Name="Microsoft.Data.Entity.Migrations.Operations.MigrationOperation" Dynamic="Required All" />
<Type Name="Microsoft.Data.Entity.Update.UpdateSqlGenerator">
<Method Name="GenerateLiteral" Signature="System.Object" Dynamic="Required" />
<Assembly Name="EntityFramework.Relational" Dynamic="Required All" />

<!-- TODO will be unnecessary after https://github.com/dotnet/corefx/pull/3917 -->
<Type Name="System.Data.Common.DbDataReader">
<MethodInstantiation Name="GetFieldValue" Arguments="System.Byte" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.Int16" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.UInt16" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.Int32" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.UInt32" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.Int64" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.UInt64" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.String" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.Single" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.Double" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.Decimal" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.TimeSpan" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.DateTime" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.DateTimeOffset" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.Guid" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.Boolean" Dynamic="Required"/>
<MethodInstantiation Name="GetFieldValue" Arguments="System.Char" Dynamic="Required"/>
</Type>
</Library>
</Directives>
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library>
<!-- TODO optimize this for types that actually need reflection -->
<Assembly Name="EntityFramework.Sqlite" Activate="All" />
<Assembly Name="EntityFramework.Sqlite" Dynamic="Required All" />
</Library>
</Directives>

0 comments on commit 31f6f24

Please sign in to comment.