Подтвердить что ты не робот

Общий способ проверки наличия сущности в инфраструктуре Entity?

Как Лучший способ проверить, существует ли объект в 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. Поскольку у сущностей могут быть разные ключи, я не могу их наследовать от общего абзаца с известным ключом для сравнения.

Я мог бы это сделать, но я беспокоюсь о производительности catching exceptions в качестве процесса проверки. Это не работает ни с тех пор, пока объект не отсоединен, свойство OriginalValues может 't:

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;
    }
}
4b9b3361

Ответ 1

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

В первом случае используйте:

public bool Exists<T>(T entity)
{
    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-код сначала не должен получать доступ к этой информации, но можно получить имя сущности. Я думаю, что что-то вроде этого должно работать:

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

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

Ответ 2

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

Я хотел бы отметить, что это не требует отражения и, кажется, работает достаточно хорошо. Единственное, о чем я не волнуюсь, это то, что TryGetObjectByKey() имеет побочный эффект присоединения найденной сущности. Поскольку я не хочу, чтобы Exists() имел этот непреднамеренный результат, мне пришлось отделить объект, если он был найден.

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);
}