简体   繁体   English

如何从 Entity Framework Core 获取实体保存顺序

[英]How to get entity save order from Entity Framework Core

When Entity Framework Core bulk saves all your changes, it uses an internal priority computed by all your foreign keys to make sure everything is saved in the right order to prevent foreign key errors.当 Entity Framework Core 批量保存所有更改时,它使用由所有外键计算的内部优先级来确保以正确的顺序保存所有内容,以防止外键错误。

How can I get this priority list from Entity Framework?如何从 Entity Framework 获取此优先级列表?

I'm constructing a synchronizer that moves a lot of entities between servers.我正在构建一个在服务器之间移动大量实体的同步器。 I need to send the entities in the right order because I cannot save everything in one go due to memory usage.我需要以正确的顺序发送实体,因为由于 memory 的使用,我无法将所有内容保存在一个 go 中。 I want to bulk save entities from the stream, but at the moment I got issues with foreign keys.我想从 stream 批量保存实体,但目前我遇到了外键问题。 It would be nice if I could use the work done by Entity Framework to get the correct save order.如果我可以使用 Entity Framework 完成的工作来获得正确的保存顺序,那就太好了。

I've done some digging inside EF Core, and found that the sorting is done inside CommandBatchPreparer.我在 EF Core 中进行了一些挖掘,发现排序是在 CommandBatchPreparer 中完成的。 This class has a protected method called TopologicalSort that sorts all queued commands for execution order.这个 class 有一个名为 TopologicalSort 的受保护方法,它对所有排队的命令进行排序以按执行顺序。 I could inherit from CommandBatchPreparer, but this is very specialized for ModificationCommand.我可以从 CommandBatchPreparer 继承,但这对于 ModificationCommand 来说非常专业。 So in my case it's not possible.所以在我的情况下这是不可能的。

I've prepared my own entity sorter based on that information.我已经根据这些信息准备了自己的实体分类器。 Keep in mind that entities that have internal self referencing properties with ForeignKey need extra handling to sort based on internal references.请记住,具有带 ForeignKey 的内部自引用属性的实体需要额外处理才能根据内部引用进行排序。

public class DbContextEntityProperty
{
    public PropertyInfo Property { get; set; }
    public Type Type { get; set; }
    public bool SelfReferencing { get; set; }
    public IEntityType EntityType { get; set; }
}

public List<DbContextEntityProperty> SortedEntityProperties()
{
    var result = new List<DbContextEntityProperty>();
    var properties = GetType().GetProperties()
        .Where(o => o.PropertyType.IsGenericType && (o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)))
        .Select(o =>
        {
            var t = o.PropertyType.GetGenericArguments()[0];
            return new DbContextEntityProperty { Property = o, Type = null, SelfReferencing = false,EntityType = Model.FindEntityType(t) };
        })
        .ToDictionary(o => o.EntityType);
    Action<DbContextEntityProperty> recursiveDependencyTraverser = null;
    recursiveDependencyTraverser = (p) =>
    {
        if (p.Type == null)
        {
            p.Type = p.EntityType.ClrType;
            foreach (var et in p.EntityType.GetDeclaredForeignKeys().Select(o => o.PrincipalEntityType))
                if (et.ClrType == p.Type)
                    p.SelfReferencing = true;
                else if (properties.TryGetValue(et, out var nextP))
                    recursiveDependencyTraverser(nextP);
            result.Add(p);
        }
    };
    foreach (var p in properties.Values)
        recursiveDependencyTraverser(p);
    return result;
}

To programmatically determine the foreign keys in your context you can use something like要以编程方式确定上下文中的外键,您可以使用类似

        Dictionary<string, Dictionary<string, IEnumerable<IForeignKey>>> foreignKeys = new Dictionary<string, Dictionary<string, IEnumerable<IForeignKey>>>();
        IEnumerable<IEntityType> ets = dbContext.Model.GetEntityTypes();
        foreach (var (et, prop) in from IEntityType et in ets
                                   let entityProps = et.GetProperties()
                                   from IProperty prop in entityProps
                                   select (et, prop))
        {
            IEnumerable<IForeignKey> fks = et.FindForeignKeys(prop);
            if(fks.Any())
            {
                if (!foreignKeys.Keys.Contains(et.DisplayName()))
                {
                    foreignKeys.Add(et.DisplayName(), new Dictionary<string, IEnumerable<IForeignKey>>());
                }

                foreignKeys[et.DisplayName()].Add(prop.Name, fks);
            }
        } 

This will create a dictionary of tables names, each dictionary entry will be a dictionary of fields and the foreign keys attached to the field ie这将创建一个表名字典,每个字典条目将是一个字段字典和附加到该字段的外键,即

IEnumerable<IForeignKey> fks = foreignKeys["TableName"]["FieldName"];

From this you should be able to work out what data is required for you to insert your records into the database.由此,您应该能够计算出将记录插入数据库所需的数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从 Entity Framework Core 中的实体获取 DbContext - Get DbContext from Entity in Entity Framework Core 如何使用 Entity Framework Core 从子表列表的每个订单中获取产品行? - How to get product row from each order of child table list using Entity Framework Core? 如何从两个表中获取数据并将其保存在Net Core Entity Framework的DTO中? - How to get data from two tables and save it in DTO in Net Core Entity Framework? 实体框架核心:如何从派生类型动态获取DbSet? - Entity Framework Core: How to dynamically get the DbSet from a derived Type? 如何从子实体框架核心获取数据到父实体框架核心? - How to get data from child to parent entity framework core? 如何获取 Entity Framework Core 中的字段总和? - How to get sum of fields in Entity Framework Core? 如何使用复合键在 model 的实体框架核心中获取单个实体? - How to get single entity in Entity Framework Core of model with composite key? 如何在 ASP.NET Core web 应用程序中使用 Entity Framework Core 从数据库中保存和检索图像? - How to save and retrieve images from database using Entity Framework Core in ASP.NET Core web application? Entity Framework Core 获取实体列名 - Entity Framework Core get entity column name 如何使用 Entity Framework 在 .NET Core 中保存用户数据 - How to save user data in .NET Core with Entity Framework
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM