Получить зависимые объекты - PullRequest
0 голосов
/ 27 февраля 2019

У меня есть приложение базы данных, использующее EntityFramework 6 и SQL Server.В случае удаления объекта.Я хотел бы показать пользователю каждую зависимую сущность, которая будет удалена с выбранной, соответствующей ограничениям ON DELETE.Прежде чем фактически удалить его.

Итак, мой вопрос:

Существуют ли какие-либо упрощенные возможности с использованием EntityFramework или, возможно, с использованием специфических запросов SQL Server непосредственно для их получения?

Спасибо большоемного.

Ответы [ 2 ]

0 голосов
/ 28 февраля 2019

Я нашел рабочее решение для моей проблемы.На всякий случай кому-то еще интересно.Я опубликую это здесь.Это основано на комментарии от Eldho.Вы можете получить зависимые объекты, используя Entity Framework.Как уже было сказано, RelationshipManager уже содержит все зависимые объекты.

Я написал два метода расширения для DbContext: Один, чтобы получить все сущности, полагающиеся на данную сущность.И один, чтобы получить все сущности, на которые опирается данная сущность.

public static class DbContextExtensions
{
/// <summary>
/// Gets all entities the given entity is relying on.
/// Will cast the result to a given Type (Entity Base Class / Interface, whatever)
/// </summary>
public static List<TEntity> GetAllDependentEntities<TEntity>(this DbContext ctx, TEntity entity)
  where TEntity : class
{
  return ctx.GetAllRelatedEntities(entity, IsRelationshipParent);
}

/// <summary>
/// Gets all Entities relying on the given entity
/// Will cast the result to a given Type (Entity Base Class / Interface, whatever)
/// </summary>
public static List<TEntity> GetAllEntitiesDependingOn<TEntity>(this DbContext ctx, TEntity entity)
  where TEntity : class
{
  return ctx.GetAllRelatedEntities(entity, IsRelationshipChild);
}

private static List<TEntity> GetAllRelatedEntities<TEntity>(this DbContext ctx, TEntity entity, Func<IRelatedEnd, bool> relationshipFilter)
  where TEntity : class
{
  var result = new List<TEntity>();

  var queue = new Queue<TEntity>();
  queue.Enqueue(entity);

  while (queue.Any())
  {
    var current = queue.Dequeue();

    var foundDependencies = ctx.GetRelatedEntitiesFrom<TEntity>(current, relationshipFilter);
    foreach (var dependency in foundDependencies)
    {
      if (!result.Contains(dependency))
        queue.Enqueue(dependency);
    }

    result.Add(current);
  }

  return result;
}


private static List<TEntity> GetRelatedEntitiesFrom<TEntity>(this DbContext ctx, object entity, Func<IRelatedEnd, bool> relationshipFilter)
  where TEntity : class
{
  var stateManager = (ctx as IObjectContextAdapter)?.ObjectContext?.ObjectStateManager;

  if (stateManager == null)
    return new List<TEntity>();

  if (!stateManager.TryGetRelationshipManager(entity, out var relationshipManager))
    return new List<TEntity>();

  return relationshipManager.GetAllRelatedEnds()
                            .Where(relationshipFilter)
                            .SelectMany(ExtractValues<TEntity>)
                            .Where(x => x != null)
                            .ToList();
}

private static IEnumerable<TEntity> ExtractValues<TEntity>(IRelatedEnd relatedEnd)
  where TEntity : class
{
  if (!relatedEnd.IsLoaded)
    relatedEnd.Load();

  if (relatedEnd is IEnumerable enumerable)
    return ExtractCollection<TEntity>(enumerable);
  else
    return ExtractSingle<TEntity>(relatedEnd);
}

private static IEnumerable<TEntity> ExtractSingle<TEntity>(IRelatedEnd relatedEnd)
  where TEntity : class
{
  var valueProp = relatedEnd.GetType().GetProperty("Value");
  var value = valueProp?.GetValue(relatedEnd);

  yield return value as TEntity;
}

private static IEnumerable<TEntity> ExtractCollection<TEntity>(IEnumerable enumerable)
{
  return enumerable.OfType<TEntity>();
}

private static bool IsRelationshipParent(IRelatedEnd relatedEnd)
  => relatedEnd.SourceRoleName.Contains("Target");

private static bool IsRelationshipChild(IRelatedEnd relatedEnd)
  => relatedEnd.TargetRoleName.Contains("Target");
}

или посмотрите здесь: https://gist.github.com/felixalmesberger/8a9fde392698e366d5cbb75853efb412

0 голосов
/ 27 февраля 2019

Этот запрос должен дать вам то, что вы ищете.В моем примере я нахожу все таблицы, связанные с моей таблицей «Клиенты».

SELECT ParentTable.Name AS ParentTable, ChildTable.Name AS ChildTable
FROM sys.foreign_keys FK 
    INNER JOIN sys.tables ParentTable ON FK.parent_object_id = ParentTable.object_id
    INNER JOIN sys.tables ChildTable ON FK.referenced_object_id = ChildTable.object_id
WHERE ParentTable.Name = 'Customers'
UNION
SELECT ParentTable.Name AS ParentTable, ChildTable.Name AS ChildTable
FROM sys.foreign_keys FK 
    INNER JOIN sys.tables ParentTable ON FK.parent_object_id = ParentTable.object_id
    INNER JOIN sys.tables ChildTable ON FK.referenced_object_id = ChildTable.object_id
WHERE ChildTable.Name = 'Customers'

Если вы не хотите вставлять весь этот SQL в свое решение, вы можете просто превратить этот запрос вView

CREATE VIEW dbo.RelatedTables
AS
SELECT ParentTable.Name AS ParentTable, ChildTable.Name AS ChildTable
FROM sys.foreign_keys FK 
    INNER JOIN sys.tables ParentTable ON FK.parent_object_id = ParentTable.object_id
    INNER JOIN sys.tables ChildTable ON FK.referenced_object_id = ChildTable.object_id

Затем запросите ваш VIEW как таблицу:

SELECT * FROM dbo.RelatedTables 
WHERE ParentTable = 'Customers' OR ChildTable = 'Customers'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...