我正在尝试实现可以使用 EF core 向任何表动态添加/更新/删除行的功能。表名称可作为字符串使用。
我尝试了几种方法,但似乎没有任何效果......
方法一:
string tablename = "someTableName";
SomeDbContext context = new SomeDbContext();
var type = context.Model.FindEntityType(tablename);
if (type != null)
{
var query = context.Set(type);
query.Add(new {
Id = 1,
someId1 = 64089,
someId2 = 64087,
comment= "some random testing" });
context.SaveChanges();
}
错误信息:
The type arguments for method 'method' cannot be inferred from the usage. Try specifying the type arguments explicitly.
方法2:
Type t = Type.GetType(Assembly.GetExecutingAssembly().GetName().Name + "." + tablename);
var dbset = context.Set(t);
错误信息:同上。
方法3:
var name = Assembly.GetExecutingAssembly().GetName().Name + tablename;
var entitytype = Type.GetType(name);
var results = context
.GetType()
.GetMethod("Set")
.MakeGenericMethod(entitytype)
.Invoke(context, null);
错误信息:
System.Reflection.AmbiguousMatchException: 'Ambiguous match found.'
任何人都可以帮我指出正确的方向吗?
我能够解析所有 3 种方法中的实体类型,但在调用 Context 上的 Set 方法时失败。
实现了简单的扩展方法,它接受
className
和 json
字符串,然后使用反射来调用适当的方法。使用 Newtonsoft.Json 进行反序列化。
使用示例:
var className = "someTableName";
var json = "{ \"id\": 1, \"name\": \"someName\" }";
context.AddEntity(className, json);
// or other methods
context.UpdateEntity(className, json);
context.RemoveEntity(className, json);
以及扩展实现:
public static class DynamicChangeTrackerExtensions
{
public static void AddEntity(this DbContext context, string className, string jsonData)
{
var entityType = GetEntityType(context, className);
_addMethod.MakeGenericMethod(entityType.ClrType).Invoke(null, new object?[] { context, jsonData });
}
public static void RemoveEntity(this DbContext context, string className, string jsonData)
{
var entityType = GetEntityType(context, className);
_removeMethod.MakeGenericMethod(entityType.ClrType).Invoke(null, new object?[] { context, jsonData });
}
public static void UpdateEntity(this DbContext context, string className, string jsonData)
{
var entityType = GetEntityType(context, className);
_updateMethod.MakeGenericMethod(entityType.ClrType).Invoke(null, new object?[] { context, jsonData });
}
static IEntityType GetEntityType(DbContext context, string className)
{
var entityType = context.Model
.GetEntityTypes()
.SingleOrDefault(et => et.ClrType.Name == className);
return entityType ?? throw new InvalidOperationException($"No class found for '{className}'");
}
static MethodInfo _addMethod = typeof(DynamicChangeTrackerExtensions).GetMethod(nameof(AddInternal), BindingFlags.NonPublic | BindingFlags.Static)!;
static MethodInfo _removeMethod = typeof(DynamicChangeTrackerExtensions).GetMethod(nameof(RemoveInternal), BindingFlags.NonPublic | BindingFlags.Static)!;
static MethodInfo _updateMethod = typeof(DynamicChangeTrackerExtensions).GetMethod(nameof(UpdateInternal), BindingFlags.NonPublic | BindingFlags.Static)!;
static T Deserialize<T>(string jsonData)
{
return JsonConvert.DeserializeObject<T>(jsonData) ?? throw new InvalidOperationException();
}
static void AddInternal<T>(this DbContext context, string jsonData)
where T : class
{
context.Set<T>().Add(Deserialize<T>(jsonData));
}
static void RemoveInternal<T>(this DbContext context, string jsonData)
where T : class
{
context.Set<T>().Remove(Deserialize<T>(jsonData));
}
static void UpdateInternal<T>(this DbContext context, string jsonData)
where T : class
{
context.Set<T>().Update(Deserialize<T>(jsonData));
}
}