实体框架 - 如何获取列?

发布于 2024-11-07 21:36:55 字数 112 浏览 0 评论 0原文

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

我如何在 C# (4.0) 中执行此操作(最好是一般情况)?

获胜的答案将是一个能够高效且最重要地通用的答案。

I wish to get a list of columns names, types and whether the column is a PK of a table object in Entity Framework.

How do I do this in C# (4.0) (ideally generically)?

The winning answer will be one that does it efficiently and most importantly generically.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

想挽留 2024-11-14 21:36:55

明白了 - 我使用了基于 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 表达式来构建例如搜索,默认情况下它将自动搜索所有列。但我还需要列名来验证,因为我将允许覆盖它,并且这些调用将通过 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
                                     };    

Got it - I used a linq based reflection query:

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

Sorted!
Thanks for the suggestions all.

FYI - I am creating a dynamic where clause using LINQ, dynamic lambda expressions to build e.g. search which will automatically search through all columns by default. But I also needed the column names to verify because I will allow this to be overridden and these calls will be done via javascript ajax post whose input cannot be trusted - so needed to verify the column names.

I used the above to place the results into a custom object with properties called FieldName, FieldType, PrimaryKey. Ta daaa.

Customise it further with

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
                                     };    
素年丶 2024-11-14 21:36:55

如果您只想要列名称,那么我得到了最佳答案:
var 属性 =(来自 typeof(YourTableName).GetProperties() 中的 t
选择 t.Name).ToList();
var name=属性[0];

if you want only column names then ,i got the best answer :
var properties = (from t in typeof(YourTableName).GetProperties()
select t.Name).ToList();
var name= properties[0];

如日中天 2024-11-14 21:36:55

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

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
        };

If you do not want to use reflection, see answer here. Replace entity name below with your entity name

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
        };
零時差 2024-11-14 21:36:55

如果有人还在寻找,这就是我的做法。
这是 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));

If anyone is still looking, Here's how I did it.
This is an extension method for the DBContext that takes a type and returns physical column names and their properties.

This utilizes object context to get physical columns list, then uses the "PreferredName" metadata property to map each column it its property.

Since it uses object context, it initiates a database connection, so the first run will be slow depending on the complexity of the context.

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);
}

To use it, just create a helper static class, and add above function; then it's as simple as calling

var tabCols = context.GetTableColumns(typeof(EntityType));
末骤雨初歇 2024-11-14 21:36:55
typeof(TableName).GetProperties().Select(x => x.Name).ToList();
typeof(TableName).GetProperties().Select(x => x.Name).ToList();
风筝有风,海豚有海 2024-11-14 21:36:55

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

查看这套教程,帮助您开始编程 - http://www .codeproject.com/KB/database/SMO_Tutorial_1.aspx
http://www.codeproject.com/KB/database/SMO_Tutorial_2.aspx

I don't have a a code sample for you, but just so that you're pointed in the right direction, you might want to look into using the Sql Management Objects (SMO); you can use this to get an object hierarchy for an Sql Server instance, which you can then enumerate and pick out the information you need.

Have a look at this set of tutorials to get you started with the programming - http://www.codeproject.com/KB/database/SMO_Tutorial_1.aspx
http://www.codeproject.com/KB/database/SMO_Tutorial_2.aspx

一张白纸 2024-11-14 21:36:55

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

        <EntityType Name="STRATEGIC_PLAN">
          <Key>
            <PropertyRef Name="Id" />
          </Key>
          <Property Type="Decimal" Name="Id" Nullable="false" Precision="8" Scale="0" annotation:StoreGeneratedPattern="None" />
          <Property Type="Decimal" Name="CreatedById" Nullable="false" Precision="8" Scale="0" />
          <Property Type="DateTime" Name="CreatedDate" Nullable="false" />
          <Property Type="Decimal" Name="DepartmentId" Nullable="false" Precision="4" Scale="0" />
          <Property Type="String" Name="Name_E" Nullable="false" MaxLength="2000" FixedLength="false" Unicode="false" />
          <Property Type="String" Name="Name_F" MaxLength="2000" FixedLength="false" Unicode="false" />
          <Property Type="Decimal" Name="UpdatedById" Precision="8" Scale="0" />
          <Property Type="DateTime" Name="UpdatedDate" />
          <Property Type="DateTime" Name="Timestamp" Nullable="false" Precision="6" annotation:StoreGeneratedPattern="Computed" />
          <NavigationProperty Name="AnnualPlans" Relationship="StrategicPlanningModel.R_51213" FromRole="STRATEGIC_PLAN" ToRole="STRAT_ANNUAL_PLAN" />
          <NavigationProperty Name="Department" Relationship="StrategicPlanningModel.R_51212" FromRole="STRATEGIC_PLAN" ToRole="DEPARTMENT" />
          <NavigationProperty Name="CreatedBy" Relationship="StrategicPlanningModel.R_51210" FromRole="STRATEGIC_PLAN" ToRole="STAFF" />
          <NavigationProperty Name="UpdatedBy" Relationship="StrategicPlanningModel.R_51211" FromRole="STRATEGIC_PLAN" ToRole="STAFF" />
          <Property Type="String" Name="Desc_E" MaxLength="2000" FixedLength="false" Unicode="false" />
          <Property Type="String" Name="Desc_F" MaxLength="2000" FixedLength="false" Unicode="false" />
          <NavigationProperty Name="Goals" Relationship="StrategicPlanningModel.R_51219" FromRole="STRATEGIC_PLAN" ToRole="STRATEGIC_PLAN_GOAL" />
        </EntityType>

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

If you're using DB First or Model First, open up the .edmx file EF generated in a text editor. It's just an XML file, and it contains everything you need. Here's an example from a model of mine. Note that I'm using Oracle's EF driver, so yours won't look identical (but it should be pretty close).

        <EntityType Name="STRATEGIC_PLAN">
          <Key>
            <PropertyRef Name="Id" />
          </Key>
          <Property Type="Decimal" Name="Id" Nullable="false" Precision="8" Scale="0" annotation:StoreGeneratedPattern="None" />
          <Property Type="Decimal" Name="CreatedById" Nullable="false" Precision="8" Scale="0" />
          <Property Type="DateTime" Name="CreatedDate" Nullable="false" />
          <Property Type="Decimal" Name="DepartmentId" Nullable="false" Precision="4" Scale="0" />
          <Property Type="String" Name="Name_E" Nullable="false" MaxLength="2000" FixedLength="false" Unicode="false" />
          <Property Type="String" Name="Name_F" MaxLength="2000" FixedLength="false" Unicode="false" />
          <Property Type="Decimal" Name="UpdatedById" Precision="8" Scale="0" />
          <Property Type="DateTime" Name="UpdatedDate" />
          <Property Type="DateTime" Name="Timestamp" Nullable="false" Precision="6" annotation:StoreGeneratedPattern="Computed" />
          <NavigationProperty Name="AnnualPlans" Relationship="StrategicPlanningModel.R_51213" FromRole="STRATEGIC_PLAN" ToRole="STRAT_ANNUAL_PLAN" />
          <NavigationProperty Name="Department" Relationship="StrategicPlanningModel.R_51212" FromRole="STRATEGIC_PLAN" ToRole="DEPARTMENT" />
          <NavigationProperty Name="CreatedBy" Relationship="StrategicPlanningModel.R_51210" FromRole="STRATEGIC_PLAN" ToRole="STAFF" />
          <NavigationProperty Name="UpdatedBy" Relationship="StrategicPlanningModel.R_51211" FromRole="STRATEGIC_PLAN" ToRole="STAFF" />
          <Property Type="String" Name="Desc_E" MaxLength="2000" FixedLength="false" Unicode="false" />
          <Property Type="String" Name="Desc_F" MaxLength="2000" FixedLength="false" Unicode="false" />
          <NavigationProperty Name="Goals" Relationship="StrategicPlanningModel.R_51219" FromRole="STRATEGIC_PLAN" ToRole="STRATEGIC_PLAN_GOAL" />
        </EntityType>

You can use an XML parser to parse the file and get what you need. The .edmx file contains data on both the entities and the SQL tables, so you'll need to make sure you're getting the right part of it to get what you want.

薄暮涼年 2024-11-14 21:36:55

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

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

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

To get only columns names without table relations eg. foreign key.

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

In DB context relations are usually marked as virtual objects (unless in my Postgres test).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文