Reputation: 40212
I've created a generic ObjectSet<T>
in my generic repository.
What I would like to get is the name
of the EntityKey of ObjectSet<T>
so that I can use it in the DataContext.GetObjectByKey
.
I've searched around and dug deep, but I can't seem to find this value anywhere in the ObjectSet
class.
Upvotes: 6
Views: 12534
Reputation: 2365
Tested with EF 6.
It will return an array of objects for each primary key value for the given DbEntityEntry.
Their maybe edge cases where this does not work - but for my simple needs works great.
Hope this helps someone else.
object[] GetPrimaryKeyValue(DbEntityEntry entry)
{
List<object> key = new List<object>();
var objectStateEntry = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity);
if (objectStateEntry.EntityKey.EntityKeyValues != null && objectStateEntry.EntityKey.EntityKeyValues.Length==1)
{
key.Add(objectStateEntry.EntityKey.EntityKeyValues[0].Value);
}
else
{
if (objectStateEntry.EntitySet.ElementType.KeyMembers.Any())
{
foreach (var keyMember in objectStateEntry.EntitySet.ElementType.KeyMembers)
{
if (entry.CurrentValues.PropertyNames.Contains(keyMember.Name))
{
var memberValue = entry.CurrentValues[keyMember.Name];
if (memberValue != null)
{
key.Add(memberValue);
}
}
}
}
}
return key.ToArray();
}
Upvotes: 0
Reputation: 1
var objContext = ((IObjectContextAdapter)this.context).ObjectContext;
var objSet = objContext.CreateObjectSet<T>();
var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entityToUpdate);
Object foundEntity;
var exits = objContext.TryGetObjectByKey(entityKey, out foundEntity);
if (exits && this.dbset.Local != null && this.dbset.Local.Contains(foundEntity) &&this.dbset.Local.Any())
{
if (entityKey.EntityKeyValues != null && entityKey.EntityKeyValues.Any())
{
DbEntityEntry<T> entry = this.context.Entry(this.dbset.Find(entityKey.EntityKeyValues.FirstOrDefault().Value));
entry.CurrentValues.SetValues(entityToUpdate);
}
}
this.context.SaveChanges();
Upvotes: 0
Reputation: 2748
I had a tough time trying to do almost the same thing, getting the primary key name and value at runtime when the type is unknown. I was just get trying to implement an auditing scheme for deletes, and every solution i find involves superfluous code that I dont really understand. The EntityKey is not available from a DbContext, which is also confusing and annoying. The last 5 lines may save you 5 hours and 1 yr of baldness. I am not attempting this for Inserts, so if you do, you need to inspect those values carefully as they may be 0 or null.
foreach(var entry in ChangeTracker.Entries<IAuditable>())
{
...
case EntityState.Deleted:
var oc = ((IObjectContextAdapter)this).ObjectContext; //this is a DbContext
EntityKey ek = oc.ObjectStateManager.GetObjectStateEntry(entry.Entity).EntityKey;
var tablename = ek.EntitySetName;
var primaryKeyField = ek.EntityKeyValues[0].Key; //assumes only 1 primary key
var primaryKeyValue = ek.EntityKeyValues[0].Value;
Upvotes: 0
Reputation: 82547
This should give you all the generic arguments (the types) for the ObjectSet:
objectSet.GetType().GetGenericArguments().First()
Upvotes: 1
Reputation: 153
Generic:
public class GenericoRepositorio<T> : IGenericoRepositorio<T> where T : class
{
protected readonly ObjectSet<T> ObjetoSet;
protected readonly ModeloContainer Contexto;
public GenericoRepositorio(ModeloContainer contexto)
{
Contexto = contexto;
ObjetoSet = Contexto.CreateObjectSet<T>();
}
public T Carregar(int id)
{
object objeto;
Contexto.TryGetObjectByKey(GetEntityKey(ObjetoSet, id), out objeto);
return (T)objeto;
}
private static EntityKey GetEntityKey<T>(ObjectSet<T> objectSet, object keyValue) where T : class
{
var entitySetName = objectSet.Context.DefaultContainerName + "." + objectSet.EntitySet.Name;
var keyPropertyName = objectSet.EntitySet.ElementType.KeyMembers[0].ToString();
var entityKey = new EntityKey(entitySetName, new[] { new EntityKeyMember(keyPropertyName, keyValue) });
return entityKey;
}
}
Upvotes: 2
Reputation: 18363
See this post that I made regarding getting the EntitySetName. For my repository, I create a property that gets the entity set name for the specific class name to do exactly what you are trying to do.
Upvotes: 1
Reputation: 26889
I looked a while ago for a nice way to do this and failed to find one. I generally end up building a GetEntityByKey extension method somewhere and within that, contatenating strings to build Entity Keys for TryGetObjectByKey calls. The general idea for building the entity key goes something like this:
internal class Program
{
private static void Main(string[] args)
{
var dc = new AdventureWorksLT2008Entities();
object c;
dc.TryGetObjectByKey(GetEntityKey(dc.Customers, 23), out c);
var customer = c as Customer;
Console.WriteLine(customer.EmailAddress);
}
private static EntityKey GetEntityKey<T>(ObjectSet<T> objectSet, object keyValue) where T : class
{
var entitySetName = objectSet.Context.DefaultContainerName + "." + objectSet.EntitySet.Name;
var keyPropertyName = objectSet.EntitySet.ElementType.KeyMembers[0].ToString();
var entityKey = new EntityKey(entitySetName, new[] {new EntityKeyMember(keyPropertyName, keyValue)});
return entityKey;
}
}
You may be able to do something similar. This example assumes a single field per EntityKey for simplicity - for multiple value keys you would need to do something slightly more sophisticated with ObjectSet<T>.ElementType.KeyMembers
and pass all your keys into the EntityKey constructor.
Upvotes: 6