我正在研究一种通过EF Core为一组表种子化的机制。如何按外键依赖关系排序DbContext的实体?由于某些表具有外键,因此需要在其他表之前播种一些表。似乎会有一个简单的API来执行这种排序,但我能找到的只是一些复杂的递归T-SQL实现。
我确信这种普遍存在的问题有一个共同的解决方案,我只是无法找到它/知道如何搜索它。
更新
因为EF Core似乎还不支持Merge/Upsert/AddOrUpdate,所以我将沿着特定于数据库(在本例中为MySQL系列)原始SQL查询的路径走下去。所以,我有一个像下面的方法,我想调用实体的集合,但我需要按照TEntityType
的外键依赖关系调用此方法。由于它本身是一个原始SQL查询而不是EF API,因此我认为EF不能以正确的依赖顺序自动神奇地更新表(响应@Gert's comment)。
private static void InsertOnDuplicateKeyUpdate<TEntityType>(DbContext dbContext) where TEntityType : class
{
var entityType = dbContext.Model.FindEntityType(typeof(TEntityType));
var properties = GetPropertiesLessValueGeneratedTimestamps(entityType);
var columns = string.Join(", ", properties.Select(x => x.Name));
var values = CreateValues<TEntityType>(properties);
var updates = CreateUpdates(properties);
var rawSqlString = "INSERT INTO " + entityType.Relational().TableName + " (" + columns + ") VALUES " +
values + " ON DUPLICATE KEY UPDATE " + updates;
dbContext.Set<TEntityType>().FromSql(rawSqlString);
dbContext.SaveChanges();
}
答案 0 :(得分:0)
Entity Framework Core 包含根据外键依赖性对实体类型进行排序所需的所有信息。我在使用 EF Core 作为表顺序源时发现的唯一问题是,需要以不同方式处理相同的表引用 - 例如,是否允许插入标识符、禁用表触发器或其他方式。
要获取可以从中获取表名、DbSet 等的实体类型列表,请使用以下函数:
private IList<IEntityType> GetDependentTables(IModel model)
{
var copied = new List<IEntityType>();
var tables = model.GetEntityTypes().Where(x => x.GetKeys().Any()).ToList();
while (tables.Count > 0)
{
var copiedCount = copied.Count;
for (var i = 0; i < tables.Count; i++)
{
var table = tables[i];
if (table.GetForeignKeys().All(x => copied.Contains(x.PrincipalEntityType) || x.DeclaringEntityType == x.PrincipalEntityType))
{
copied.Add(table);
tables.RemoveAt(i);
break;
}
}
if (copiedCount == copied.Count)
{
throw new InvalidOperationException("Circular foreign keys found in remaining tables: " + string.Join(",", tables.Select(x => x.Name)));
}
}
return copied.Where(x => x.BaseType == null).ToList();
}
用法:
var tableEntityTypes = GetDependentTables(myDbContext.Model);