【问题标题】:Entity Framework - how do I get the columns?实体框架 - 我如何获取列?
【发布时间】:2011-08-28 17:37:33
【问题描述】:

我希望获取列名、类型以及该列是否是实体框架中表对象的 PK 的列表。

如何在 C# (4.0) 中执行此操作(理想情况下是通用的)?

成功的答案将是一个有效且最重要的是通用的答案。

【问题讨论】:

  • 有什么用途,在什么情况下?我的意思是,对于 EF,您有实体,那么为什么不简单地反映您的模型实体并通过可能存在的命名约定找出 PK?
  • 为什么我的帖子被否决了?如果您认为这是一个不好的问题 - 请发表评论,我会解释更多,而不仅仅是破坏我的帖子。
  • @johnny 是的 - 我正在尝试使用表达式构建 where 子句。我有一个动态构建的 where 子句,其中包含动态构建的 lambda 表达式,为每列添加一个 .contains - 但我需要表属性来构建默认的属性名称集合并验证字段名称的自定义传递。到目前为止一切正常 - 只是缺少 EF 表列
  • @Femaref - 请解释编辑帖子的原因?
  • 被删掉的部分并没有为手头的问题增加任何内容,而且总的来说,无论如何,对 SO 都不赞成。

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


【解决方案1】:

仅获取没有表关系的列名,例如。外键。

var columnNames = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(p => p.CanRead && !p.GetGetMethod()!.IsVirtual)
            .Select(property => property.Name)
            .ToList();

在 DB 上下文中,关系通常被标记为虚拟对象(除非在我的 Postgres 测试中)。

【讨论】:

  • 当然你不能依赖虚拟修饰符。另请参阅“以及该列是否为 PK”。如果不访问 EF 自己的元数据,就不可能做到这一点。
【解决方案2】:
typeof(TableName).GetProperties().Select(x => x.Name).ToList();

【讨论】:

  • 虽然它适用于列名,但仍然返回并不总是很好的外键和关系名称。
【解决方案3】:

如果有人还在寻找,我就是这样做的。 这是 DBContext 的扩展方法,它接受一个类型并返回物理列名及其属性。

这利用对象上下文获取物理列列表,然后使用“PreferredName”元数据属性将每个列映射到其属性。

由于它使用对象上下文,它会发起一个数据库连接,所以第一次运行会很慢,具体取决于上下文的复杂程度。

public static IDictionary<String, PropertyInfo> GetTableColumns(this DbContext ctx, Type entityType)
{
    ObjectContext octx = (ctx as IObjectContextAdapter).ObjectContext;
    EntityType storageEntityType = octx.MetadataWorkspace.GetItems(DataSpace.SSpace)
        .Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>()
        .Single(x => x.Name == entityType.Name);

    var columnNames = storageEntityType.Properties.ToDictionary(x => x.Name,
        y => y.MetadataProperties.FirstOrDefault(x => x.Name == "PreferredName")?.Value as string ?? y.Name);

    return storageEntityType.Properties.Select((elm, index) =>
            new {elm.Name, Property = entityType.GetProperty(columnNames[elm.Name])})
        .ToDictionary(x => x.Name, x => x.Property);
}

要使用它,只需创建一个辅助静态类,并添加上述函数即可;那么它就像调用一样简单

var tabCols = context.GetTableColumns(typeof(EntityType));

【讨论】:

  • 这是最佳答案,因为它返回物理列名称,不一定与 EF 属性名称相同。
【解决方案4】:

如果你只想要列名,我得到了最好的答案:
var properties = (from t in typeof(YourTableName).GetProperties() select t.Name).ToList(); var name= properties[0];

【讨论】:

  • 我没有能力,否则我会给你100。
【解决方案5】:

如果您不想使用反射,请参阅答案here。将下面的实体名称替换为您的实体名称

var cols = from meta in ctx.MetadataWorkspace.GetItems(DataSpace.CSpace)
                       .Where(m=> m.BuiltInTypeKind==BuiltInTypeKind.EntityType)
                    from p in (meta as EntityType).Properties
                       .Where(p => p.DeclaringType.Name == "EntityName")
                   select new
                      {
                       PropertyName = p.Name,
                       TypeUsageName = p.TypeUsage.EdmType.Name, //type name
                       Documentation = p.Documentation != null ?               
                                       p.Documentation.LongDescription : null //if primary key
        };

【讨论】:

  • 什么是 ctx 以及如何处理它?是先用于模型还是数据库,因为我使用的是代码优先
  • 在 3.5 中它是 objectcontext 实例,在以后的 EF 版本中它是您正在使用的 dbcontext 实例。使用 var ctx = new MyEntities.... 的示例
  • 我在 .Net 4.5 EF Code FIrst 上,我的 DBContext 没有 MetadataWorkspace 属性
  • 你能把dbcontext转换成对象上下文吗:((IObjectContextAdapter)dbContext).ObjectContext;或查看stackoverflow.com/questions/8059900/…
  • 感谢工作 var adapter = (IObjectContextAdapter)this; var childNavProperties = adapter.ObjectContext.MetadataWorkspace.GetItems(DataSpace.CSpace) .Where(item => item.BuiltInTypeKind == BuiltInTypeKind.EntityType) .SelectMany(item => ((EntityType)item).NavigationProperties)
【解决方案6】:

知道了 - 我使用了基于 linq 的反射查询:

IEnumerable<FieldList> properties = from p in typeof(T).GetProperties()
                                    where (from a in p.GetCustomAttributes(false)
                                    where a is EdmScalarPropertyAttribute   
                                    select true).FirstOrDefault()

排序! 谢谢大家的建议。

仅供参考 - 我正在使用 LINQ 创建一个动态 where 子句,动态 lambda 表达式来构建例如search 默认情况下会自动搜索所有列。但我还需要验证列名,因为我将允许它被覆盖,并且这些调用将通过输入不可信的 javascript ajax post 完成 - 因此需要验证列名。

我使用上述方法将结果放入一个自定义对象中,该对象具有名为 FieldName、FieldType、PrimaryKey 的属性。哒哒哒。

使用

进一步自定义
IEnumerable<FieldList> properties = from p in typeof(T).GetProperties()
                                    where (from a in p.GetCustomAttributes(false)
                                    where a is EdmScalarPropertyAttribute
                                    select true).FirstOrDefault()
                                    select new FieldList
                                    {
                                       FieldName = p.Name,
                                       FieldType = p.PropertyType,
                                       FieldPK = p.GetCustomAttributes(false).Where(a => a is EdmScalarPropertyAttribute && ((EdmScalarPropertyAttribute)a).EntityKeyProperty).Count() > 0
                                     };    

【讨论】:

  • @boomhauer 请参阅下面的非反射方法答案
【解决方案7】:

如果您使用的是 DB First 或 Model First,请打开在文本编辑器中生成的 .edmx 文件 EF。它只是一个 XML 文件,它包含您需要的所有内容。这是我的一个模型的例子。请注意,我使用的是 Oracle 的 EF 驱动程序,因此您的驱动程序看起来并不相同(但应该非常接近)。

键>

您可以使用 XML 解析器来解析文件并获得所需的内容。 .edmx 文件包含实体和 SQL 表的数据,因此您需要确保获得正确的部分才能获得所需的内容。

【讨论】:

  • 这很酷 - 我肯定会回到这个,但我仍然在 4.0 上,我没有先看代码(还)只是普通的 EF 4.0。
  • 然后就可以了。 :) Code First 是它无法工作的情况,因为 code first 中没有 edmx 文件。
  • 酷!抱歉 - 午饭后困了,哈哈,我会看看,让你知道我是怎么得到的 - 干杯!
【解决方案8】:

我没有给你的代码示例,但为了让你指向正确的方向,你可能想研究使用 Sql 管理对象 (SMO);您可以使用它来获取 Sql Server 实例的对象层次结构,然后您可以枚举并挑选出您需要的信息。

看看这套教程,让你开始编程 - http://www.codeproject.com/KB/database/SMO_Tutorial_1.aspx http://www.codeproject.com/KB/database/SMO_Tutorial_2.aspx

【讨论】:

  • No No - 我想检查代码中的 ef 表对象而不是 sql 表。 IE。我需要将表格添加到 ef 图时生成的 ef 类的属性名称
  • @Dan B - “管理员”删除了文本 Ready, steady....GO! Thanks, Dan.。这篇文章是如何因这一变化而失去部分意义的?
  • @Yakimych - 那是我的错误 - 我认为还有更多。我想我有一个句子,然后我删除了它,但我认为它在。你是怎么发现的?我很想知道我们不应该写的那种东西,因为这似乎对这篇非常短的文章没有任何损害。我现在已经删除了我不准确的评论。你能告诉谁投了我的帖子吗?
  • @Dan B - 如果你点击他编辑的地方,你可以看到编辑历史。它向您展示了他的变化。
  • @Dan B - 此外,如果您出于某种原因不同意对帖子的编辑,可以将其还原。不,您看不到谁赞成或反对您的帖子。不过,我同意你的观点,投反对票的用户应该发表评论,解释原因。
猜你喜欢
  • 2014-04-14
  • 1970-01-01
  • 1970-01-01
  • 2019-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多