简体   繁体   English

带索引的实体框架代码生成

[英]Entity Framework Code Generation with Indexes

有没有办法告诉.NET 4 ADO.NET实体的SQL生成器为特定列创建索引?

Indices are not supported natively, but if you head to the "Influencing the DDL Generation" section of this article you can see how to add this custom functionality to an existing template. 指数本身不支持,但是如果你的头的“影响的DDL生成”一节这个文章中,你可以看到这个自定义功能添加到现有的模板。

In the article's example, the new index in your EDMX's CSDL would look something like this: 在本文的示例中,EDMX的CSDL中的新索引如下所示:

<Property ... >
  <myExtensions:Index indexName="Seat" edmx:CopyToSSDL="true"/>
</Property>

But to get this working you would have to modify a few things (see the link I provided for the details). 但是要使此工作正常,您必须修改一些内容(有关详细信息,请参见我提供的链接)。 Firstly, you'd have to declare that "myExtensions" namespace on the schema node: 首先,您必须在架构节点上声明“ myExtensions”命名空间:

<!-- CSDL content -->
<edmx:ConceptualModels>
  <Schema [...] xmlns:myExtensions="http://www.microsoft.com/userExtensions">
  [...]
</edmx>

Secondly, you'd have to modify the template found at: 其次,您必须修改位于以下位置的模板:

\\Microsoft Visual Studio 10.0\\Common7\\IDE\\Extensions\\Microsoft\\Entity Framework Tools\\DBGen\\SSDLToSQL10.tt \\ Microsoft Visual Studio 10.0 \\ Common7 \\ IDE \\ Extensions \\ Microsoft \\ Entity Framework Tools \\ DBGen \\ SSDLToSQL10.tt

The solution requires Linq, so add this to the top of the template: 该解决方案需要Linq,因此请将其添加到模板顶部:

<#@ assembly name="System.Xml.Linq" #>

And then add this to the bottom: 然后将其添加到底部:

-- Creating index for table based on custom extensions --
<#
   foreach (EntitySet entitySet in Store.GetAllEntitySets())
   {
     string tableName = Id(entitySet.GetTableName());
     string schemaName = Id(entitySet.GetSchemaName());
     EdmProperties props = entitySet.ElementType.Properties;
     foreach (EdmProperty ep in props.Where(p =>
                           p.TypeUsage.EdmType is PrimitiveType))
     {
        MetadataProperty meta = ep.MetadataProperties.FirstOrDefault(mp => mp.Name == "http://www.microsoft.com/userExtensions:Index");
        if (meta != null)
        {
            System.Xml.Linq.XElement e = meta.Value as System.Xml.Linq.XElement;
            System.Xml.Linq.XAttribute attr = e.Attributes().FirstOrDefault(a => a.Name == "indexName");
            string indexName = attr.Value;     
            // create an index for specified column
#>
CREATE INDEX [IX_<#=indexName#>]
ON <#if (!IsSQLCE) {#>[<#=schemaName#>].<#}#>[<#=tableName#>]
([<#=indexName#>]);
<#
         }
     }   
   }
#>

Most of that could be pretty easily modified to fit your needs. 其中大多数可以很容易地修改以满足您的需求。 The article goes into more of the details, but the most important line in the above code is the one which fetches that custom "Index" extension node: 本文将介绍更多细节,但是以上代码中最重要的一行是获取自定义“ Index”扩展节点的那一行:

MetadataProperty meta = ep.MetadataProperties.FirstOrDefault(mp => mp.Name == "http://www.microsoft.com/userExtensions:Index");

Hope that helps! 希望有帮助!

Complementing Smudge's answer, there are some tricks that need to be done for this to work in EF 5. 为了补充Smudge的回答,需要做一些技巧才能使它在EF 5中起作用。

For instance, edmx:CopyToSSDL="true" doesn't work right off the bat. 例如,edmx:CopyToSSDL =“ true”不能立即使用。 You have to do some hacks: 您必须进行一些修改:

<Schema xmlns="http://schemas.microsoft.com/ado/2009/11/edm" xmlns:cg="http://schemas.microsoft.com/ado/2006/04/codegeneration"
              xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" Namespace="CPEData" Alias="Self"
              xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" annotation:UseStrongSpatialTypes="false"
              xmlns:myExtensions="http://www.microsoft.com/userExtensions"
              xmlns:edmxv2="http://schemas.microsoft.com/ado/2008/10/edmx" >

And then in the custom property (notice the edmxv2): 然后在自定义属性中(注意edmxv2):

<myExtensions:Index edmxv2:CopyToSSDL="true" IndexName="Name" Columns="Name" >

See this link for more info. 有关更多信息,请参见此链接

Also, I did change some of the T4 code to make it more easy. 另外,我确实更改了一些T4代码以使其更容易。 I took this example as a working base to accomplish a more flexible custom elements syntax. 我以该示例为基础,以实现更灵活的自定义元素语法。

You could add a custom element at the end of the EntityType element for instance (you don't have to put it inside a <Property></Property> tag): 例如,您可以在EntityType元素的末尾添加一个自定义元素(不必将其放在<Property></Property>标记内):

<myExtensions:Index edmxv2:CopyToSSDL="true" IndexName="Name" Columns="Name" >
    Custom metadata (not needed)
</myExtensions:Index>

And then modify the .tt template: 然后修改.tt模板:

-- --------------------------------------------------
-- Creating all Indexes based on custom extensions   
-- --------------------------------------------------

<#
   foreach (EntitySet entitySet in Store.GetAllEntitySets())
   {
     string tableName = Id(entitySet.GetTableName());
     string schemaName = Id(entitySet.GetSchemaName());
     var props = entitySet.ElementType.MetadataProperties.Where(p => p.Name == "http://www.microsoft.com/userExtensions:Index");
     foreach (MetadataProperty meta in props)
     {
        System.Xml.Linq.XElement e = meta.Value as System.Xml.Linq.XElement;
        string indexName = e.Attributes().FirstOrDefault(a => a.Name == "IndexName").Value;
        string columnsName = e.Attributes().FirstOrDefault(a => a.Name == "Columns").Value;
        // create an index for specified column
#>
CREATE INDEX [IX_<#=indexName#>]
ON <#if (!IsSQLCE) {#>[<#=schemaName#>].<#}#>[<#=tableName#>]
([<#=columnsName#>]);
<#

     }   
   }
#>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM