I am trying to create a generic method using EF4 to find the primary key of an object.
我正在尝试使用EF4创建一个通用方法来查找对象的主键。
example
public string GetPrimaryKey<T>()
{
...
}
To give more info I am working off of the Tekpub StarterKit and below is the class I am trying to get up and running
为了提供更多信息,我正在使用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
}
}
}
4 个解决方案
#1
17
So I was finally able to find out how to get this to work. I wish I hadn't lost the link to the blog I read last night as I didn't write the code.
所以我终于能够找到如何使这个工作。我希望我没有丢失我昨晚读到的博客的链接,因为我没有写代码。
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;
}
I hope this helps someone else. All I can say is that it should be a little clearer on how to do this.
我希望这有助于其他人。我只能说,如何做到这一点应该更清楚一些。
#2
15
There is a property on each EF4 entity called EntityKey
which contains an array of EntityKeyValues
(array is there in case of compound key).
每个名为EntityKey的EF4实体都有一个属性,它包含一个EntityKeyValues数组(如果是复合键,则为数组)。
You could reference this directly on your entity instance or create a generic helper method that does this under the covers. If I can test-drive some sample code, I'll post it up here.
您可以直接在您的实体实例上引用它,或者创建一个通用的帮助方法来实现这一点。如果我可以测试一些示例代码,我会在这里发布。
Edit: The EntityKeyValue is a KeyValuePair<TKey, TValue>
where the key
is the primary key field of the entity and the value
is the associated value.
编辑:EntityKeyValue是KeyValuePair
E.g., I have an entity called Company
whose primary key is the field Symbol
.
例如,我有一个名为Company的实体,其主键是字段Symbol。
var firstCompany = (from c in context.Companies select c).FirstOrDefault();
var kvp = firstCompany.EntityKey.EntityKeyValues[0];
// kvp shows {[Symbol, FOO]}
In my sandbox, I noticed this property was null
when I created the entity in code. But once I read the entity from the database, it was correctly populated. So, it appears that the EF4 concept of a primary key only comes in to play once it hits the database. Although, you are free to set it explicitly ahead of time, if you wish.
在我的沙箱中,我注意到当我在代码中创建实体时,此属性为null。但是一旦我从数据库中读取实体,它就被正确填充了。因此,似乎主键的EF4概念只有在它到达数据库时才能发挥作用。虽然如果您愿意,可以提前明确地设置它。
#3
3
I assume many people stop by this post just by looking "Entity framework how to find the primary key?" regardless EF version (like me). So I wanted to mentioned that with EF 6.1, you can also create an extension methods to get the primary key. Following is the example and works perfectly fine.
我假设很多人只是通过查看“实体框架如何找到主键?”来阻止这篇文章。无论EF版本(像我一样)。所以我想提一下,使用EF 6.1,您还可以创建扩展方法来获取主键。以下是示例,完美无缺。
PS: I am not 100% sure, if that would work with composite and compound keys tho.
PS:我不是100%肯定,如果那可以使用复合键和复合键。
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();
}
}
}
#4
2
this seems needlessly long? I have had the same need, and using the suggestions above (by SethO and denis_n), i am using:
这似乎是不必要的长?我有同样的需求,并使用上面的建议(由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();
Hope this helps anyone who is interested
希望这可以帮助任何有兴趣的人
#1
17
So I was finally able to find out how to get this to work. I wish I hadn't lost the link to the blog I read last night as I didn't write the code.
所以我终于能够找到如何使这个工作。我希望我没有丢失我昨晚读到的博客的链接,因为我没有写代码。
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;
}
I hope this helps someone else. All I can say is that it should be a little clearer on how to do this.
我希望这有助于其他人。我只能说,如何做到这一点应该更清楚一些。
#2
15
There is a property on each EF4 entity called EntityKey
which contains an array of EntityKeyValues
(array is there in case of compound key).
每个名为EntityKey的EF4实体都有一个属性,它包含一个EntityKeyValues数组(如果是复合键,则为数组)。
You could reference this directly on your entity instance or create a generic helper method that does this under the covers. If I can test-drive some sample code, I'll post it up here.
您可以直接在您的实体实例上引用它,或者创建一个通用的帮助方法来实现这一点。如果我可以测试一些示例代码,我会在这里发布。
Edit: The EntityKeyValue is a KeyValuePair<TKey, TValue>
where the key
is the primary key field of the entity and the value
is the associated value.
编辑:EntityKeyValue是KeyValuePair
E.g., I have an entity called Company
whose primary key is the field Symbol
.
例如,我有一个名为Company的实体,其主键是字段Symbol。
var firstCompany = (from c in context.Companies select c).FirstOrDefault();
var kvp = firstCompany.EntityKey.EntityKeyValues[0];
// kvp shows {[Symbol, FOO]}
In my sandbox, I noticed this property was null
when I created the entity in code. But once I read the entity from the database, it was correctly populated. So, it appears that the EF4 concept of a primary key only comes in to play once it hits the database. Although, you are free to set it explicitly ahead of time, if you wish.
在我的沙箱中,我注意到当我在代码中创建实体时,此属性为null。但是一旦我从数据库中读取实体,它就被正确填充了。因此,似乎主键的EF4概念只有在它到达数据库时才能发挥作用。虽然如果您愿意,可以提前明确地设置它。
#3
3
I assume many people stop by this post just by looking "Entity framework how to find the primary key?" regardless EF version (like me). So I wanted to mentioned that with EF 6.1, you can also create an extension methods to get the primary key. Following is the example and works perfectly fine.
我假设很多人只是通过查看“实体框架如何找到主键?”来阻止这篇文章。无论EF版本(像我一样)。所以我想提一下,使用EF 6.1,您还可以创建扩展方法来获取主键。以下是示例,完美无缺。
PS: I am not 100% sure, if that would work with composite and compound keys tho.
PS:我不是100%肯定,如果那可以使用复合键和复合键。
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();
}
}
}
#4
2
this seems needlessly long? I have had the same need, and using the suggestions above (by SethO and denis_n), i am using:
这似乎是不必要的长?我有同样的需求,并使用上面的建议(由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();
Hope this helps anyone who is interested
希望这可以帮助任何有兴趣的人