Как я понимаю, у вас есть объект, который не отслеживается контекстом, и вы хотите использовать EF для запроса эквивалентного объекта в базе данных. (Затем вы хотите обновить базу данных со значениями объекта, но это будет отдельный вопрос.)
Вы можете использовать метод Find, чтобы получить сущность из базы данных, если вы знаете ее значения первичного ключа. Сложный бит получает значения первичного ключа в общем виде. Это то, что мы хотим сделать проще в будущей версии EF, но на данный момент я подготовил несколько методов расширения, чтобы помочь.
Прежде всего, давайте получим имена первичных ключей для заданного типа. Это сложный бит. Она требует опускаясь до ObjectContext и используя MetadataWorkspace:
public static IEnumerable<string> PrimayKeysFor(
this DbContext context,
object entity)
{
Contract.Requires(context != null);
Contract.Requires(entity != null);
return context.PrimayKeysFor(entity.GetType());
}
public static IEnumerable<string> PrimayKeysFor(
this DbContext context,
Type entityType)
{
Contract.Requires(context != null);
Contract.Requires(entityType != null);
var metadataWorkspace =
((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;
var objectItemCollection =
(ObjectItemCollection)metadataWorkspace.GetItemCollection(DataSpace.OSpace);
var ospaceTypes = metadataWorkspace.GetItems<EntityType>(DataSpace.OSpace);
var ospaceType = ospaceTypes
.FirstOrDefault(t => objectItemCollection.GetClrType(t) == entityType);
if (ospaceType == null)
{
throw new ArgumentException(
string.Format(
"The type '{0}' is not mapped as an entity type.",
entityType.Name),
"entityType");
}
return ospaceType.KeyMembers.Select(k => k.Name);
}
}
Теперь мы можем добавить метод расширения, который использует это, чтобы получить ключевые значения для данного объекта (которые не должны быть отслежены):
public static object[] PrimayKeyValuesFor(this DbContext context, object entity)
{
Contract.Requires(context != null);
Contract.Requires(entity != null);
var entry = context.Entry(entity);
return context.PrimayKeysFor(entity)
.Select(k => entry.Property(k).CurrentValue)
.ToArray();
}
Как только у нас это, это довольно легко использовать, чтобы найти объект в базе данных, соответствующий данному объекту, ничего не зная об объекте. Например:
var databaseOrderLine =
context.Set<OrderLine>().Find(context.PrimayKeyValuesFor(orderLine));