创建用于枚举的dbset的通用列表

时间:2019-06-26 15:01:56

标签: c# entity-framework-core

我正在编写一个简单的.NET Core库,以使用EF Core将数据从一个SQL数据库复制到另一个SQL数据库。我正在尝试找到一种创建通用列表的方法,而不是为每个DbSet复制代码,我可以对其进行枚举并为其创建一些逻辑。

我试图创建一个元组来保存有关源表和目标表的信息,但是无法定义通用DbSet。

我还使用泛型创建了一个自定义类来设置DbSet类型,但是由于每种类的类型不同,因此无法将其添加到列表中。

示例方法:

public void Execute()
{
    var source = new SourceContext();
    var destination = new DestinationContext();

    Console.WriteLine("Processing table A");
    destination.RemoveRange(destination.TableA);
    destination.SaveChanges();

    destination.AddRange(source.TableA.AsNoTracking().ToList());
    destination.SaveChanges();
}

为了不为其他表复制代码,请尝试使用元组,例如

var tables = new List<Tuple<string, DbSet<T>, DbSet<T>>>
{
    Tuple.Create("Table A", source.TableA, destination.TableA),
    Tuple.Create("Table B", source.TableB, destination.TableB)
}; 

问题在于使用通用DbSet定义元组,因为要添加的每个项目都有不同的类型。

希望创建一个类来定义表格,例如

internal class Table<TEntity> where TEntity : class
{
    internal string Name {get; set;}
    internal DbSet<TEntity> Source {get; set;}
    internal DbSet<TEntity> Destination {get; set;}

    internal Table(string name, DbSet<TEntity> source, DbSet<TEntity> destination)
    {
        Name = name;
        Source = source;
        Destination = destination;
    }
}

但是我该如何创建没有特定类型的List

var tables = new List<T>
{
    new Table<TableA>("Table A", source.TableA, destination.TableA),
    new Table<TableB>("Table B", source.TableB, destination.TableB)
};

List必须使用类型<T>进行实例化。

2 个答案:

答案 0 :(得分:0)

通常的做法是使用List<Something>,其中Something是所有类型都将支持的通用基类或接口。目前,您最接近的是object,但您可能可以向您的{{1 }}。但是,问题是:有用吗?充其量您可以暴露Table<TEntity>;如果没有Name,您不能有用地谈论DbSet<T>,除了可能是非通用<T> / IEnumerable之外;所以:

IQueryable

并使用internal interface ITable { string Name {get;} IQueryable Source {get;} IQueryable Destination {get;} Type Type {get;} } 吗?

List<ITable>变为:

Table<T>

答案 1 :(得分:0)

由于EF Core没有非泛型的Set方法,@ DavidG建议使Execute成为泛型。您只需为每种类型“跳板”一点点反射即可。

var source = new SourceContext();
var destination = new DestinationContext();

var tables = new List<(string, Type)>
{
    ("Table A", typeof(TableA)),
    ("Table B", typeof(TableB))
};

var executeMethodInfo = GetType().GetMethod("Execute");
foreach (var (displayName, entityType) in tables)
{
    executeMethodInfo.MakeGenericMethod(entityType)
        .Invoke(this, new object[] { displayName, source, destination });
}

通用的Execute方法如下:

public void Execute<T>(string displayName, SourceContext source, DestinationContext destination)
    where T : class
{
    Console.WriteLine($"Processing {displayName}");

    destination.RemoveRange(destination.Set<T>());
    destination.SaveChanges();

    destination.AddRange(source.Set<T>().AsNoTracking().ToList());
    destination.SaveChanges();
}