Универсальный способ проверить, существует ли сущность в Entity Framework?


аналогично лучший способ проверить, существует ли объект в Entity Framework?

Я ищу общий способ проверки сущности в DbSet. Что-то вроде этого, что не работает:

private DbContext DbContext { get; set; }

private DbSet<T> DbSet { get; set; }

public Boolean Exists(T entity) {
    return ((from item in this.DbSet
             where item == entity
             select item).Count() > 0);
}

строку where item == entity работает в LINQ to SQL, но, по-видимому, не с LINQ to Entities. Поскольку сущности могут иметь разные ключи, я не могу наследовать их все от общего абстракта с известным ключом для сравнения.

я мог бы сделать это, но я беспокоюсь о производительности ловли исключений в качестве процесса проверки это тоже не работает, так как до тех пор, пока объект отсоединен OriginalValues свойство не может быть получено:

public Boolean Exists(T entity) {
    try {
        var current = this.DbContext.Entry(entity).OriginalValues;
        // Won't reach this line if the entity isn't in the database yet
        return true;
    }
    catch (Exception ex) {
        return false;
    }
}
2 56

2 ответа:

вы хотите универсальный способ проверить, если сущность была загружена контекстом или универсальный способ запроса базы данных, если сущность существует?

для первого случая использования:

public bool Exists<T>(T entity) where T: class
{
    return this.Set<T>().Local.Any(e => e == entity);
}

для последнего случая использования (он также будет проверять загруженные объекты):

public bool Exists<T>(params object[] keys)
{
    return (this.Set<T>().Find(keys) != null);
}

Edit:

EF code first не должен получать доступ к такого рода информации, но можно получить имя ключей сущностей. Я думаю, что-то вроде этого должно быть работа:

var objContext = ((IObjectContextAdapter)dbContext).ObjectContext;
var objSet = objContext.CreateObjectSet<T>();
var keyNames = objSet.EntitySet.ElementType.KeyMembers.Select(m => m.Name);

но это все не имеет смысла. Вам нужен общий подход, но ваши сущности не предоставляют необходимую информацию, чтобы разрешить общий подход. Теперь вы говорите, что даже не знаете ключевых ценностей. Использование этого "общего" подхода потребует отражения и ручного построения дерева выражений.

спасибо @Ladislav для получения меня в правильном направлении. Вот код для универсального Exists() метод.

Я хотел бы отметить, что это не требует размышлений и, кажется, достаточно хорошо. Единственное, что я не в восторге от этого TryGetObjectByKey() имеет побочный эффект присоединения найденного объекта. Так как я не хочу!--1--> чтобы получить этот непреднамеренный результат, я должен отсоединить объект, если он был найден.

public Boolean Exists(T entity) {
    var objContext = ((IObjectContextAdapter)this.DbContext).ObjectContext;
    var objSet = objContext.CreateObjectSet<T>();
    var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entity);

    Object foundEntity;
    var exists = objContext.TryGetObjectByKey(entityKey, out foundEntity);
    // TryGetObjectByKey attaches a found entity
    // Detach it here to prevent side-effects
    if (exists) {
        objContext.Detach(foundEntity);
    }

    return (exists);
}