首页 > 解决方案 > 为枚举创建一个通用的 dbset 列表

问题描述

我正在编写一个简单的 .NET 核心库,以使用 EF Core 将数据从一个 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需要用 type 实例化<T>

标签: c#entity-framework-core

解决方案


您通常这样做的方式是使用List<Something>whereSomething是所有类型都支持的通用基类或接口。目前,您拥有的最接近的是object.,但您也许可以将一些非泛型基类/接口添加到您的Table<TEntity>. 但是,问题是:它有用吗?充其量你可以暴露Name; 你不能有用地谈论DbSet<T>没有 a 的 a <T>,除非可能是非通用的IEnumerable/ IQueryable;所以:

internal interface ITable
{
    string Name {get;}
    IQueryable Source {get;}
    IQueryable Destination {get;}
    Type Type {get;}
}

并使用List<ITable>

哪里Table<T>变成:

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

    string ITable.Name => Name;
    IQueryable ITable.Source => Source;
    IQueryable ITable.Destination => Destination;
    Type ITable.Type => typeof(T);

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

推荐阅读