EntityFramework Получить объект по ID?
Можно ли с помощью Generics получить объект из моей EntityFramework, не зная тип?
Я думаю о чем-то вроде:
public T GetObjectByID<T>(int id)
{
return (from i in myDatabase.T where i.ID == id select i);
}
Это выполнимо? Могу ли я использовать Reflection, чтобы как-то взять T.GetType().Name
и использовать его для таблицы?
ИЗМЕНИТЬ
Еще одно зависание - это то, что не все доступные мне таблицы используют "ID" в качестве уникального имени столбца.
Ответы
Ответ 1
Наконец, решила проблему с этим:
http://pastebin.com/kjXUKBNS
Чтобы вызвать код, я использую это:
// Get the id of the object we are saving
PropertyInfo prop = GetProperty<TEntity>(entity, entity.EntityKey.EntityKeyValues[0].Key);
string entityID = prop.GetValue(entity, null).ToString();
// Get the current version of this object
var originalEntity = GetEntity<TEntity>(PropertyEquals, entityID);
Это делает предположение, что первичный ключ, который вы ищете, является первым в списке Первичных ключей.
Ответ 2
Вы можете определить интерфейс, реализованный всеми вашими объектами:
public interface IEntity
{
int Id { get; }
}
и метод для извлечения вашего объекта:
public T GetObjectById<T>(int id) where T : class, IEntity
{
return context.CreateObjectSet<T>().SingleOrDefault(e => e.Id == id);
}
Вы также можете использовать аналогичный подход к тому, который указан в связанном вопросе. Вам просто нужно использовать другой метод для получения вашей сущности:
public virtual T GetByKey<T>(int id) where T : class, IEntity
{
string containerName = context.DefaultContainerName;
string setName = context.CreateObjectSet<T>().EntitySet.Name;
// Build entity key
var entityKey = new EntityKey(containerName + "." + setName, "Id", id);
return (TEntity)Context.GetObjectByKey(entityKey);
}
Разница в том, что первый метод всегда запрашивает базу данных, даже если вы уже загрузили экземпляр в контекст, тогда как второй подход сначала проверяет, загружен ли экземпляр. Метод не настолько эффективен, потому что он снова и снова создает эти имена. Здесь - более общий подход, который может работать с любым типом ключа и именем и здесь - это подход к работе со сложными ключами.
Ни один из этих методов напрямую не работает с наследованием - вы должны предоставить базовый тип, чтобы он работал.
Ответ 3
Я думаю, что метод Find()
может выполнять то, что вы ищете (DbSet.Find Method).
var someEntity = dbSet.Find(keyValue);
Ответ 4
Трудно сделать полностью общее решение, потому что Entities может иметь составные ключи, но это будет работать для простого случая с одним ключом.
Ключ должен ограничивать T
типом System.Data.Objects.DataClasses.EntityObject
, который затем имеет свойство EntityKey
(которое представляет первичный ключ).
static T GetById<T>(object id) where T : EntityObject
{
using (var context = new MyEntities())
{
return context.CreateObjectSet<T>()
.SingleOrDefault(t => t.EntityKey.EntityKeyValues[0].Value == id);
}
}
Ответ 5
Другой способ получить сущность от id на enitiy framework
public T Get<T>(int id) where T : EntityObject;
{
var ObjectSet = _context.CreateObjectSet<T>();
var PropName = ObjectSet.EntitySet.ElementType.KeyMembers[0].ToString();
return ObjectSet.Where("it." + PropName + "=" + id).FirstOrDefault();
}
Результат
SELECT TOP (1)
[Extent1].[CatId] AS [CatId],
[Extent1].[CatName] AS [CatName],
[Extent1].[CatType] AS [CatType],
FROM [dbo].[Categories] AS [Extent1]
WHERE [Extent1].[CatId] = 1
Ответ 6
Я думаю, что это могло бы помочь
public static TEntity Find<TEntity>(this ObjectSet<TEntity> set, object id) where TEntity : EntityObject
{
using (var context = new MyObjectContext())
{
var entity = set.Context.CreateObjectSet<TEntity>();
string keyName = entity.FirstOrDefault().EntityKey.EntityKeyValues.FirstOrDefault().Key;
return entity.Where("it." + keyName + " = " + id).FirstOrDefault();
}
}
Ответ 7
Одна вещь, с которой я работал, - это определить интерфейс "KeyComparator":
public interface IHasKeyComparator<TObject> {
Expression<Func<TObject, bool>> KeyComparator { get; }
}
И затем вы можете реализовать его на каком-либо объекте даже с помощью многозначного ключа:
public sealed class MultiKeyedObject : IHasKeyComparator<MultiKeyedObject> {
public int ID1 { get; set; }
public string ID2 { get; set; }
readonly Expression<Func<MultiKeyedObject, bool>> mKeyComparator;
public Expression<Func<MultiKeyedObject, bool>> KeyComparator {
get { return mKeyComparator; }
}
public MultiKeyedObject() {
mKeyComparator = other => other.ID1 == ID1 && other.ID2 == ID2;
}
}
И можно использовать его в общем случае, если вы предоставляете ограничение:
public TObject Refresh<TObject>(TObject pObject)
where TObject : IHasKeyComparator<TObject> {
return this.Set<TObject>().Single(pObject.KeyComparator);
}
Выполнение этого способа требует, чтобы у вас был экземпляр объекта, хотя, хотя вы можете заполнить пустым ключом значения, а затем использовать его, чтобы вытащить из БД.
Ответ 8
Здесь метод, который я использую для получения объекта Entity по идентификатору.
public TEntity GetByKey<TEntity>(object keyValue) where TEntity : class
{
EntityKey key = GetEntityKey<TEntity>(keyValue);
object originalItem;
if (ObjectContext.TryGetObjectByKey(key, out originalItem))
{
return (TEntity)originalItem;
}
return default(TEntity);
}
Вы можете найти это более надежное решение, чем некоторые из приведенных выше. Я использовал его как часть общего репозитория во многих проектах. Надеюсь, вам это поможет.