2

Some body can help me to create a generic GetByID method, The challenge here, is that I Have many entities, each of them has a different PK Name.

I See several example with a Generic GetByID, but many of them has the same PK Name like (id).

Thanks.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
Jean-Francois
  • 1,899
  • 4
  • 35
  • 73

2 Answers2

6

Here is example of base repository class for repositories build for entity with single property key. The GetByKey method is independent on key name or type.

using System;
using System.Data;
using System.Data.Metadata.Edm;
using System.Data.Objects;
using System.Linq;

namespace EntityKeyTest
{
    // Base repository class for entity with simple key
    public abstract class RepositoryBase<TEntity, TKey> where TEntity : class
    {
        private readonly string _entitySetName;
        private readonly string _keyName;

        protected ObjectContext Context { get; private set; }
        protected ObjectSet<TEntity> ObjectSet { get; private set; }

        protected RepositoryBase(ObjectContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            Context = context;
            ObjectSet = context.CreateObjectSet<TEntity>();
            // Get entity set for current entity type
            var entitySet = ObjectSet.EntitySet;
            // Build full name of entity set for current entity type
            _entitySetName = context.DefaultContainerName + "." + entitySet.Name;
            // Get name of the entity's key property
            _keyName = entitySet.ElementType.KeyMembers.Single().Name;
        }

        public virtual TEntity GetByKey(TKey key)
        {
            // Build entity key
            var entityKey = new EntityKey(_entitySetName, _keyName, key);
            // Query first current state manager and if entity is not found query database!!!
            return (TEntity)Context.GetObjectByKey(entityKey);
        }
        // Rest of repository implementation
    }
}

There is one trickler when using this code. If you don't use generated class derived from ObjectContext and you use ObjectContext directly you must manually set DefaultContainerName used by your model.

Edit:

This method is for classic EF. I can think about version for Code-first if needed.

Rich_Rich
  • 427
  • 3
  • 15
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • 1
    @Jean-Francois: Just extract the code you need to build your generic method. I wrote it this way to reduce number of searching for entity set name and key name. The basis is: If you want generic "GetByKey" you must find the key in metadata. – Ladislav Mrnka Mar 14 '11 at 15:58
  • @LadislavMrnka - this doesn't work if the entity has not been saved to the database but just inserted locally - GetObjectByKey says it cannot find an entity with that key even though when I call oc.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified) I see there is an object state entry for that entity. – Ventsyslav Raikov Apr 09 '13 at 08:25
  • @Bond: Yes it doesn't work for not persisted entities because they don't have a real key yet. If you want to get them you must use `GetObjectStateEntries` and search result set for your entity. – Ladislav Mrnka Apr 09 '13 at 08:30
  • @LadislavMrnka - yes, that's exactly what I'm trying to do, but I want to search them in a generic way. I tried oc.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted).Where(e => e.EntityKey.Equals(entityKey)) but to no avail, the EntityKey of the added(but not yet saved) entity shows EntityKeyValues: null, IsTemporary: true which I guess makes the search to fail. My keys are not auto generated(they are strings). – Ventsyslav Raikov Apr 09 '13 at 08:48
  • 1
    @Bond: It doesn't matter if they are autogenerated or not. If your entity is in added state it has just temporary key because you can still change it (while changing key for existing entity is not allowed). – Ladislav Mrnka Apr 09 '13 at 09:52
  • @LadislavMrnka - thanks, that must be it. I'll try to work around that some other way. – Ventsyslav Raikov Apr 09 '13 at 11:00
0

I know this answer is old and specifically tagged as EF-4, but Find() or FindAsync() are the correct solution as of EF-6 fwiw:

https://msdn.microsoft.com/en-us/library/dn246936(v=vs.113).aspx

Lee Richardson
  • 8,331
  • 6
  • 42
  • 65