Я пытаюсь создать динамический dbcontext, который не использует DataAnnotation, предоставляемую EF.Динамический вызов в EntityFramework EntityTypeConfiguration <>. HasKey
Таким образом, в моем переназначении пустоты OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
сгенерировать динамический универсальный тип, который имеет все атрибуты и тип, необходимый для ключа:
Dictionary<Int32, PropertyInfo> dictIndex = new Dictionary<Int32, PropertyInfo>();
...
Type dynamicType = LinqRuntimeTypeBuilder.GetDynamicType(dictIndex.OrderBy(x => x.Key).Select(x => x.Value));
IEnumerable<MemberBinding> bindings = dynamicType.GetFields().Select(p => Expression.Bind(p, Expression.Property(paramEx, dictIndex.Select(x => x.Value).FirstOrDefault(x => x.Name == p.Name)))).OfType<MemberBinding>();
ConstructorInfo ci = dynamicType.GetConstructor(Type.EmptyTypes);
Expression selector = Expression.Lambda(Expression.MemberInit(Expression.New(ci), bindings), paramEx);
var HasKey = config.GetType().GetMethod("HasKey").MakeGenericMethod(dynamicType);
HasKey.Invoke(config, new[] { selector });
Я нашел LinqRuntimeTypeBuilder
в качестве ответа на другой вопрос и поправил код чтобы соответствовать моим потребностям:
public static class LinqRuntimeTypeBuilder
{
private static AssemblyName assemblyName = Assembly.GetExecutingAssembly().GetName();//new AssemblyName() { Name = "DynamicLinqTypes" };
private static ModuleBuilder moduleBuilder = null;
private static Dictionary<string, Type> builtTypes = new Dictionary<string, Type>();
static LinqRuntimeTypeBuilder()
{
moduleBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run).DefineDynamicModule(assemblyName.Name);
}
private static string GetTypeKey(Dictionary<string, Type> fields)
{
//TODO: optimize the type caching -- if fields are simply reordered, that doesn't mean that they're actually different types, so this needs to be smarter
string key = string.Empty;
key = "<>f__AnonymousType1`1";
foreach (var field in fields)
key += field.Key + ";" + field.Value.Name + ";";
return key;
}
public static Type GetDynamicType(Dictionary<string, Type> fields)
{
if (null == fields)
throw new ArgumentNullException("fields");
if (0 == fields.Count)
throw new ArgumentOutOfRangeException("fields", "fields must have at least 1 field definition");
try
{
Monitor.Enter(builtTypes);
string className = GetTypeKey(fields);
if (builtTypes.ContainsKey(className))
return builtTypes[className];
TypeBuilder typeBuilder = moduleBuilder.DefineType(className, TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit | TypeAttributes.NotPublic,typeof(object));
GenericTypeParameterBuilder[] gaBuilders = typeBuilder.DefineGenericParameters(fields.Select(x => "T" + x.Value.Name).ToArray());
int i = 0;
foreach (var field in fields)
typeBuilder.DefineField(field.Key, gaBuilders[i++], FieldAttributes.Public);
builtTypes[className] = typeBuilder.CreateType().MakeGenericType(fields.Select(x => x.Value).ToArray());
return builtTypes[className];
}
catch (Exception ex)
{
}
finally
{
Monitor.Exit(builtTypes);
}
return null;
}
private static string GetTypeKey(IEnumerable<PropertyInfo> fields)
{
return GetTypeKey(fields.ToDictionary(f => f.Name, f => f.PropertyType));
}
public static Type GetDynamicType(IEnumerable<PropertyInfo> fields)
{
return GetDynamicType(fields.ToDictionary(f => f.Name, f => f.PropertyType));
}
}
Но Призывание HasKey бросает исключение:
System.Reflection.TargetInvocationException: Ein Aufrufziel hat einen Ausnahmefehler verursacht. ---> System.InvalidOperationException: The properties expression `'Param_0 => new {LfdVtgNr = Param_0.LfdVtgNr}'` is not valid. The expression should represent a property: C#: 't => t.MyProperty' VB.Net: 'Function(t) t.MyProperty'. When specifying multiple properties use an anonymous type: C#: 't => new { t.MyProperty1, t.MyProperty2 }' VB.Net: 'Function(t) New With { t.MyProperty1, t.MyProperty2 }'.
bei System.Data.Entity.Utilities.ExpressionExtensions.GetSimplePropertyAccessList(LambdaExpression propertyAccessExpression)
bei System.Data.Entity.ModelConfiguration.EntityTypeConfiguration`1.HasKey[TKey](Expression`1 keyExpression)
--- Ende der internen Ausnahmestapelüberwachung ---
bei System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
bei System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
если я делаю статический вызов этого с использованием modelBuilder.Configurations.HasKey('Param_0 => new {LfdVtgNr = Param_0.LfdVtgNr})
, он работает, но не динамически.
Конечно, я мог бы использовать другой способ, но я хочу понять ошибку.
Буду признателен за любую помощь.
BTW: Есть любой Symbol/sourceerver для EntityFramework тоже? –