Могу ли я динамически получать отношения сущностей в SaveChanges ()? - PullRequest
2 голосов
/ 15 января 2020

TargetFramework: netstandard2.0

EntityFrameworkCore: 2.2.6

У меня есть следующий код в OnModelCreating:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<SlotOrder>(entity =>
    {
        entity.Property(e => e.Id).HasConversion(
            v => v.ToString(),
            v => new Guid(v));
    });

    modelBuilder.Entity<SlotOrderDetail>(entity =>
    {
        entity.Property(e => e.Id).HasConversion(
            v => v.ToString(),
            v => new Guid(v));

        entity.HasOne<SlotOrder>()
            .WithMany()
            .HasForeignKey(c => c.SlotOrderId);
    });
}

Я не использую свойства навигации и нуждаюсь загрузить все отношения определенного объекта в SaveChangesAsyn c. В моем случае, если сущностью является SlotOrder, мне нужно определить, что она имеет дочернюю сущность SlotOrderDetail:

public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
    ChangeTracker.DetectChanges();

    var utcNow = DateTime.UtcNow;

    var added = ChangeTracker.Entries()
        .Where(t => t.State == EntityState.Added)
        .Select(t => t.Entity)
        .ToList();

    added.ForEach(entity =>
    {
        if (entity is IAuditable auditable)
        {
            auditable.CreatedAt = utcNow;
            auditable.UpdatedAt = utcNow;
        }

        // var relationships = ...
    });

    return base.SaveChangesAsync(cancellationToken);
}

Любая подсказка, как это сделать?

Ответы [ 2 ]

2 голосов
/ 15 января 2020

Метаданные отношений предоставляются интерфейсом IForeignKey .

При наличии IEntityType существует два метода, которые можно использовать для получения информации для отношений сущностей - GetForeignKeys , которая возвращает отношения, в которых сущность является зависимой, и GetReferencingForeignKeys , которые возвращают отношения, в которых сущность является принципалом.

В вашем случае не выбирайте свойство .Entity, используйте EntityEntry, который дает вам доступ к свойству IEntityType через Metadata, например

var addedEntries = ChangeTracker.Entries()
    .Where(t => t.State == EntityState.Added)
    .ToList();

addedEntries.ForEach(entry =>
{
    if (entry.Entity is IAuditable auditable)
    {
        auditable.CreatedAt = utcNow;
        auditable.UpdatedAt = utcNow;
    }

    var foreignKeys = entry.Metadata.GetForeignKeys();
    var referencingForeignKeys = entry.Metadata.GetReferencingForeignKeys();
});
1 голос
/ 19 января 2020

Я не думаю, что это возможно сделать, но у меня просто есть другая идея, что-то вроде этого. Создайте новую функцию для SaveChanges, затем загрузите все.

В любом создаваемом вами классе.

public IQueryable<T> CommitLoad<T>() where T : class
    {
        db.SaveChanges();
        var list = db.Set<T>().AsQueryable();

        var key = db.Model.FindEntityType(typeof(T)).FindPrimaryKey().Properties.FirstOrDefault();
        var foreignkeys = key.GetContainingPrimaryKey().GetReferencingForeignKeys();

        if (foreignkeys.Count() > 0)
        {
            foreach (var item in foreignkeys)
                list = list.Include<T>(item.DeclaringEntityType.DisplayName());
        }

        return list;
    }

Любой класс или страница

public IQueryable<SlotOrder> GetTest()
    {
        //Save record to table

        //After saving record, savechanges + load all
        var list = CommitLoad<SlotOrder>();

        return list;
    }

Вот скриншот результата

See this result screenshot

...