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”作为其唯一的列名。
答案 0 :(得分:30)
您可以定义所有实体实施的界面:
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);
}
您也可以使用与linked question中提供的方法类似的方法。您只需使用其他方法来获取您的实体:
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);
}
不同之处在于,即使您已将实例加载到上下文,第一种方法也始终查询数据库,而第二种方法首先检查实例是否已加载。该方法效率不高,因为它反复构建这些名称。 Here是更通用的方法,可以使用任何键类型和名称,here是使用复杂键的方法。
这两种方法都不能直接用于继承 - 你必须提供基类型才能使它工作。
答案 1 :(得分:23)
我认为Find()
方法可以做你想要的事情(DbSet.Find Method)。
var someEntity = dbSet.Find(keyValue);
答案 2 :(得分:5)
很难制作完全通用的解决方案,因为实体可以使用复合键,但这适用于简单的单键案例。
关键是要将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);
}
}
答案 3 :(得分:3)
最后解决了这个问题:
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);
这假设您正在搜索的主键是主键列表中的第一个。
答案 4 :(得分:3)
从实体框架上的id获取实体的另一种方法
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
答案 5 :(得分:2)
我认为这可能会有所帮助
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();
}
}
答案 6 :(得分:0)
我做过的一件事就是定义一个“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);
}
这样做需要您拥有该对象的实例,尽管您可以使用键值填充空的实例,然后使用它从数据库中提取。
答案 7 :(得分:-1)
这是我用来通过ID获取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);
}
您可能会发现这是一个比上面提供的更强大的解决方案。我在很多项目中都将它用作通用存储库的一部分。希望它可以帮助你。