我正在编写一个简单的.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>
进行实例化。
答案 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();
}