我正在使用Visual Studio 2012中的MVC 4(C#)项目。我正在使用实体框架,它利用* .edmx文件来建模现有数据库。我的目标是实现数据库审计以跟踪对数据库所做的任何更改。使用数据库表中的字段自动生成类 - 我相信非常标准的东西。
尝试检索这些生成的类的主键时遇到问题。实体框架不会将[Key]属性分配给类属性。我尝试通过扩展创建的部分类并自己分配此属性来解决此问题。将它直接添加到生成的类中可以正常工作。如果我尝试“伙伴类”方法,我稍后会在代码执行中收到以下错误:“实体{类名}没有[Key]属性。”
自动生成的课程:
public partial class List
{
public List()
{
this.Tasks = new HashSet<Task>();
}
public int Id { get; set; }
public string ListName { get; set; }
}
扩展(伙伴)类:
[MetadataType(typeof(ListMetaData))]
public partial class List
{
private class ListMetaData
{
[Key]
public int Id { get; set; }
}
}
代码段:
var property = dbEntry.Entity.GetType().GetProperties().FirstOrDefault(
p => p.GetCustomAttributes(typeof(KeyAttribute), true).Any());
if (property == null)
throw new InvalidOperationException(string.Format(
"Entity {0} has no [Key] attribute.", dbEntry.Entity.GetType().Name));
string keyName = property.Name;
我正在覆盖DbContext中的SaveChanges()方法以跟踪正在进行的更改。上面的代码片段显示了函数中的一部分代码,该函数检查DbEntityEntry对象(dbEntry)以获取主键。
答案 0 :(得分:1)
List
类是实体框架类还是ListMetaData
类?如果它是List
类,则该类中的Id
属性根本没有任何属性。嵌套Id
类的ListMetaData
属性具有属性,这是一个完全不同的属性。
如果您希望ListMetaData
类具有该属性,我会将该类的表添加到模型中(如果还没有该类),取消嵌套该类并使其公开。
答案 1 :(得分:1)
感谢大家的建议。我最终做的是修改* .tt模板以自动将[Key]属性和System.ComponentModel.DataAnnotations指令添加到动态生成的类文件中。
答案 2 :(得分:0)
你可以检查一些事情。
您的部分类与实体类在同一名称空间中吗?
您的部分班级是否在同一个项目中?
尝试将ListMetaData
课程的访问级别更改为公开
或内部,也许没有嵌套吗?
答案 3 :(得分:0)
我做了类似这样的事情,希望它有所帮助,并且是你所追求的:
public string[] GetKeyNames<TEntity>() where TEntity : class
{
var set = ((IObjectContextAdapter)this).ObjectContext.CreateObjectSet<TEntity>();
var entitySet = set.EntitySet;
return entitySet.ElementType.KeyMembers.Select(k => k.Name).ToArray();
}
我在DBContext本身上创建了它作为公共方法。然后你会这样称呼它:
var keys = context.GetKeyNames<List>();
使用this作为灵感。
您不需要元数据类来标识密钥 - 该信息将存储在edmx文件中。您通常使用元数据添加验证,例如[必需]等。
答案 4 :(得分:0)
使用EF 6.1,您还可以创建扩展方法来获取主键。 以下是示例,并且完美地运行。
PS:我不是百分百肯定,如果这可以使用复合键和复合键。
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();
}
}
}