Entity Framework 4: Как найти первичный ключ?
Я пытаюсь создать общий метод, используя EF4, чтобы найти первичный ключ объекта.
Пример
public string GetPrimaryKey<T>()
{
...
}
Чтобы дать больше информации, я работаю над Tekpub StarterKit, а ниже - класс, который я пытаюсь запустить и запустить
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Objects;
using System.Data.Objects.ELinq;
using System.Data.Linq;
using Web.Infrastructure.Storage.EF4;
namespace Web.Infrastructure.Storage {
public class EFSession:ISession {
PuzzleEntities _db;//This is an ObjectContext
public EFSession() {
_db = new PuzzleEntities();
}
public void CommitChanges() {
_db.SaveChanges();
}
/// <summary>
/// Gets the table provided by the type T and returns for querying
/// </summary>
private ObjectSet<T> GetObjectSet<T>() where T:class {
return _db.CreateObjectSet<T>();
}
private T GetByPrimaryKey<T>() where T: class
{
.....
}
public void Delete<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T: class{
foreach (T item in All<T>().Where(expression))
{
GetObjectSet<T>().DeleteObject(item);
}
}
public void Delete<T>(T item) where T : class {
GetObjectSet<T>().DeleteObject(item);
}
public void DeleteAll<T>() where T : class {
foreach(T item in All<T>())
{
GetObjectSet<T>().DeleteObject(item);
}
}
public void Dispose() {
_db.Dispose();
}
public T Single<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T:class {
return GetObjectSet<T>().SingleOrDefault(expression);
}
public IQueryable<T> All<T>() where T : class {
return GetObjectSet<T>().AsQueryable();
}
public void Add<T>(T item) where T : class {
GetObjectSet<T>().AddObject(item);
}
public void Add<T>(IEnumerable<T> items) where T : class {
foreach (T item in items)
{
GetObjectSet<T>().AddObject(item);
}
}
public void Update<T>(T item) where T : class {
//nothing needed here
}
}
}
Ответы
Ответ 1
Итак, я наконец смог узнать, как заставить это работать. Мне жаль, что я не потерял ссылку на блог, который я прочитал прошлой ночью, так как я не писал код.
public T GetByPrimaryKey<T>(int id) where T : class
{
return (T)_db.GetObjectByKey(new EntityKey(_db.DefaultContainerName + "." + this.GetEntityName<T>(), GetPrimaryKeyInfo<T>().Name, id));
}
string GetEntityName<T>()
{
string name = typeof(T).Name;
if (name.ToLower() == "person")
return "People";
else if (name.Substring(name.Length - 1, 1).ToLower() == "y")
return name.Remove(name.Length - 1, 1) + "ies";
else if (name.Substring(name.Length - 1, 1).ToLower() == "s")
return name + "es";
else
return name + "s";
}
private PropertyInfo GetPrimaryKeyInfo<T>()
{
PropertyInfo[] properties = typeof(T).GetProperties();
foreach (PropertyInfo pI in properties)
{
System.Object[] attributes = pI.GetCustomAttributes(true);
foreach (object attribute in attributes)
{
if (attribute is EdmScalarPropertyAttribute)
{
if ((attribute as EdmScalarPropertyAttribute).EntityKeyProperty == true)
return pI;
}
else if (attribute is ColumnAttribute)
{
if ((attribute as ColumnAttribute).IsPrimaryKey == true)
return pI;
}
}
}
return null;
}
Надеюсь, это поможет кому-то другому. Все, что я могу сказать, это то, что должно быть немного ясно, как это сделать.
Ответ 2
На каждом объекте EF4 с именем EntityKey
есть свойство, которое содержит массив EntityKeyValues
(массив существует в случае составного ключа).
Вы можете ссылаться на это непосредственно на свой экземпляр объекта или создать общий вспомогательный метод, который делает это под обложками. Если я смогу тестировать некоторый пример кода, я отправлю его здесь.
Изменить: EntityKeyValue - это KeyValuePair<TKey, TValue>
, где key
- это поле первичного ключа для объекта, а value
- связанное значение.
Например, у меня есть объект под названием Company
, первичным ключом которого является поле Symbol
.
var firstCompany = (from c in context.Companies select c).FirstOrDefault();
var kvp = firstCompany.EntityKey.EntityKeyValues[0];
// kvp shows {[Symbol, FOO]}
В моей песочнице я заметил, что это свойство было null
, когда я создал объект в коде. Но как только я прочитал объект из базы данных, он был правильно заполнен. Таким образом, кажется, что концепция EF4 первичного ключа входит в игру только после того, как она попадает в базу данных. Хотя, вы можете установить его явно заблаговременно, если хотите.
Ответ 3
Это кажется излишне длинным?
У меня была такая же потребность, и, используя приведенные выше предложения (с помощью SethO и denis_n), я использую:
//get the primary key field name and location for the table
var primaryFieldName = entry.EntitySet.ElementType.KeyMembers[0].Name ;
int primaryFieldLocation = entry.CurrentValues.GetOrdinal(primaryFieldName);
//gets the value pair for the primary key (returns field name + value)
var primaryField = entry.EntityKey.EntityKeyValues[primaryFieldLocation];
String primaryFieldValue = primaryField.Value.ToString();
Надеюсь, это поможет любому, кто заинтересован.
Ответ 4
Я предполагаю, что многие люди останавливаются на этом посту, просто взглянув на "Entity framework, как найти первичный ключ"? независимо от версии EF (например, я). Поэтому я хотел упомянуть, что с EF 6.1 вы также можете создать методы расширения для получения первичного ключа.
Ниже приведен пример и прекрасно работает.
PS: Я не уверен на 100%, если это будет работать с составными и составными ключами tho.
using System;
using System.Data.Entity;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Linq;
namespace System.Data.Entity
{
public static class DbContextExtensions
{
public static string[] GetKeyNames<TEntity>(this DbContext context)
where TEntity : class
{
return context.GetKeyNames(typeof(TEntity));
}
public static string[] GetKeyNames(this DbContext context, Type entityType)
{
var metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;
// Get the mapping between CLR types and metadata OSpace
var objectItemCollection = ((ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace));
// Get metadata for given CLR type
var entityMetadata = metadata
.GetItems<EntityType>(DataSpace.OSpace)
.Single(e => objectItemCollection.GetClrType(e) == entityType);
return entityMetadata.KeyProperties.Select(p => p.Name).ToArray();
}
}
}
Исходный источник