Общий способ проверить, существует ли сущность в Entity Framework? - PullRequest
56 голосов
/ 16 мая 2011

Аналогично Лучший способ проверить, существует ли объект в 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 ]

83 голосов
/ 16 мая 2011

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

Для первого случая используйте:

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 сначала не предназначен для доступа к информации такого рода, но возможно получить имя ключей сущности. Я думаю, что-то подобное должно работать:

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

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

21 голосов
/ 19 мая 2011

Спасибо @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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...