如何动态添加行到EF中的表

问题描述 投票:0回答:1

我正在尝试实现可以使用 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 方法时失败。

c# entity-framework-core dbcontext
1个回答
0
投票

实现了简单的扩展方法,它接受

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));
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.