Search code examples
c#genericsentity-framework-4.1

Generic Way to Check If Entity Exists In Entity Framework?


Similar to Best way to check if object exists in Entity Framework?

I'm looking for a generic way to check for an entity in a DbSet. Something like this, which doesn't work:

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

The line where item == entity works in LINQ to SQL, but apparently not with LINQ to Entities. Since the entities may have different keys I can't have them all inherit from a common abstract with a known key for comparison.

I could do this, but I'm worried about the performance of catching exceptions as a verification process This doesn't work either since as long as the entity is detached the OriginalValues property can't be obtained:

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

Solution

  • Do you want generic way to check if entity was loaded by context or generic way to query database if entity exists?

    For the former case use:

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

    For the latter case use (it will check loaded entities as well):

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

    Edit:

    EF code first is not supposed to access this kind of information but it is possible to get name of entity keys. I think something like that should work:

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

    But this all doesn't make sense. You want generic approach but your entities doesn't share necessary information to allow generic approach. Now you say that you even don't know key values. Using this "generic" approach will require reflection and manual building of expression tree.