将[Key]属性分配给Entity Framework生成的类 - MVC4 C#

时间:2013-12-20 14:17:06

标签: c# entity-framework asp.net-mvc-4

我正在使用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)以获取主键。

5 个答案:

答案 0 :(得分:1)

List类是实体框架类还是ListMetaData类?如果它是List类,则该类中的Id属性根本没有任何属性。嵌套Id类的ListMetaData属性具有属性,这是一个完全不同的属性。

如果您希望ListMetaData类具有该属性,我会将该类的表添加到模型中(如果还没有该类),取消嵌套该类并使其公开。

答案 1 :(得分:1)

感谢大家的建议。我最终做的是修改* .tt模板以自动将[Key]属性和System.ComponentModel.DataAnnotations指令添加到动态生成的类文件中。

答案 2 :(得分:0)

你可以检查一些事情。

  1. 您的部分类与实体类在同一名称空间中吗?

  2. 您的部分班级是否在同一个项目中?

  3. 尝试将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();
        }
    }
}

Original Source