0

我有一个 CodeFluent 实体模型,例如:

<cf:project defaultNamespace="S5T" xmlns:cf="http://www.softfluent.com/codefluent/2005/1" xmlns:cfx="http://www.softfluent.com/codefluent/modeler/2008/1" xmlns:cfmy="http://www.softfluent.com/codefluent/producers.mysql/2012/1" xmlns:cfom="http://www.softfluent.com/codefluent/producers.model/2005/1" xmlns:cfasp="http://www.softfluent.com/codefluent/producers.aspnet/2011/1" xmlns:cfaz="http://www.softfluent.com/codefluent/producers.sqlazure/2011/1" xmlns:cfps="http://www.softfluent.com/codefluent/producers.sqlserver/2005/1" defaultKeyPropertyTypeName="long" maxParameterNameLength="62" defaultConcurrencyMode="None" persistencePropertyNameFormat="{1}" defaultMethodAllowDynamicSort="false" defaultProducerProductionFlags="Default, Overwrite, RemoveDates" defaultMethodDistinct="false" createDefaultMethodForms="true" createDefaultApplication="false" createDefaultHints="false" productionFlags="Default, Overwrite, RemoveDates">
  <cf:import path="Default.Surface.cfp" />
  <cf:producer name="SQL Server" typeName="CodeFluent.Producers.SqlServer.SqlServerProducer, CodeFluent.Producers.SqlServer">
    <cf:configuration produceViews="true" targetDirectory="..\Model7Bom\Persistence" connectionString="Server=MY-MACHINE\SQLEXPRESS;Database=model7;Integrated Security=true;Application Name=S5T;Password=MyPassword;User ID=MyUser" cfx:targetProject="..\Model7Bom\Model7Bom.vbproj" cfx:targetProjectLayout="Update, DontRemove" />
  </cf:producer>
  <cf:entity name="User" namespace="S5T">
    <cf:property name="Id" key="true" cfps:hint="CLUSTERED" />
    <cf:property name="Name" />
    <cf:property name="Roles" typeName="{0}.RoleCollection" relationPropertyName="Users" />
  </cf:entity>
  <cf:entity name="Role" namespace="S5T">
    <cf:property name="Id" key="true" cfps:hint="CLUSTERED" />
    <cf:property name="Name" />
    <cf:property name="Users" typeName="{0}.UserCollection" relationPropertyName="Roles" />
  </cf:entity>
</cf:project>

我可以使用 cfps:hint="CLUSTERED" 成功地装饰两个实体上的 cf:property name="Id "。这让我 Sql Server 生产者正确输出

CONSTRAINT [PK_Use_Id_Use] PRIMARY KEY CLUSTERED
CONSTRAINT [PK_Rol_Id_Rol] PRIMARY KEY CLUSTERED

而不是默认的非集群。

如何使用模型生成的第三张表来实现这一点,以适应多对多关系?

默认情况下,创建表生成的代码片段如下:

CREATE TABLE [dbo].[Role_Users_User_Roles] (
 [Id] [bigint] NOT NULL,
 [Id2] [bigint] NOT NULL,
 CONSTRAINT [PK_Roe_Id_Id2_Roe] PRIMARY KEY NONCLUSTERED
 (

  [Id],
  [Id2]
 ) ON [PRIMARY]
)

但是,如果我用 cfps:hint="CLUSTERED" 装饰这两个属性,如下所示:

cf:property name="Roles" typeName="{0}.RoleCollection" relationPropertyName="Users" cfps:hint="CLUSTERED" /

cf:property name="Users" typeName="{0}.UserCollection" relationPropertyName="Roles" cfps:hint="CLUSTERED" /

我得到了一个使用 PRIMARY KEY CLUSTERED 为 TABLE [dbo].[Role_Users_User_Roles] 中的 PK 生成的片段,但是,此外,我得到了一个不希望的效果,即为添加关系生成了一个不正确的脚本(生成的文件名 ...relations_add.sql ), 如:

ALTER TABLE [dbo].[Role_Users_User_Roles] WITH NOCHECK ADD CONSTRAINT [FK_Roe_Id_Id_Rol] FOREIGN KEY (
 [Id]
) REFERENCES [dbo].[Role](

 [Id]
) CLUSTERED

连同来自 Sql Server 的错误:

错误 3 SQL80001:'CLUSTERED' 附近的语法不正确。

和 CodeFluent 生产者错误:

CodeFluentRuntimeDatabaseException: CF4116: 在第 2 行执行文件 ...path..._relations_add.sql 语句

我需要生成的三个表中的所有三个 PK 集群,但不需要语法错误的副作用来生成关系。

4

1 回答 1

2

不支持开箱即用。在 a 关系上声明的提示很少使用,更多地是作为外键提示而不是列提示。您可以使用几个选项来执行此操作。

最简单的方法是使用生成后的 .SQL 脚本手动添加集群设置。此处对此进行了描述:如何:使用 Microsoft SQL Server producer 执行自定义 T-SQL 脚本

您还可以使用 Patch Producer 从文件中删除 CLUSTERED 词,一旦它被创建:Patch Producer

否则,这是另一个解决方案,它涉及我在此处作为示例编写的一个方面。您可以将以下 XML 片段保存为文件,并将其作为模型中的一个方面进行引用。

这个方面会将 CLUSTERED 提示添加到从具有 CLUSTERED 键的实体推断的所有多对多表的主键中。它将在创建和运行表脚本之前添加提示,并在之后将其删除(因此它不会在relations_add脚本中结束)。

<cf:project xmlns:cf="http://www.softfluent.com/codefluent/2005/1">
    <!-- assembly references -->
    <?code @reference name="CodeFluent.Producers.SqlServer.dll" ?>
    <?code @reference name="CodeFluent.Runtime.Database.dll" ?>

    <!-- namespace includes -->
    <?code @namespace name="System" ?>
    <?code @namespace name="System.Collections.Generic" ?>
    <?code @namespace name="CodeFluent.Model.Code" ?>
    <?code @namespace name="CodeFluent.Model.Persistence" ?>
    <?code @namespace name="CodeFluent.Model.Code" ?>

    <!-- add global code to listen to inference steps -->
    <?code 
        Project.StepChanging += (sender1, e1) =>
        {
            if (e1.Step == ImportStep.End) // hook before production begins (end of inference pipeline)
            {
                var modifiedTables = ProjectHandler.AddClusteredHint(Project);
                // get sql server producer and hook on production events
                var sqlProducer = Project.Producers.GetProducerInstance<CodeFluent.Producers.SqlServer.SqlServerProducer>();
                sqlProducer.Production += (sender, e) =>
                {
                    // determine what SQL file has been created
                    // we want to remove hints once the table_diffs has been created, before relations_add is created
                    string script = e.GetDictionaryValue("filetype", null);
                    if (script == "TablesDiffsScript")
                    {
                        ProjectHandler.RemoveClusteredHint(modifiedTables);
                    }
                };
            }
        };
    ?>

    <!-- add member code to handle inference modification -->
    <?code @member
    public class ProjectHandler
    {
        public static IList<Table> AddClusteredHint(Project project)
        {
            var list = new List<Table>();
            foreach (var table in project.Database.Tables)
            {
                // we're only interested by tables inferred from M:M relations
                if (table.Relation == null || table.Relation.RelationType != RelationType.ManyToMany)
                    continue;

                // check this table definition is ok for us
                if (table.RelationKeyColumns.Count < 1 || table.RelationRelatedKeyColumns.Count < 1)
                    continue;

                // check clustered is declared on both sides
                string keyHint = GetSqlServerProducerHint(table.RelationKeyColumns[0].Property);
                string relatedKeyHint = GetSqlServerProducerHint(table.RelationKeyColumns[0].Property);
                if (keyHint.IndexOf("clustered", StringComparison.OrdinalIgnoreCase) < 0 ||
                    relatedKeyHint.IndexOf("clustered", StringComparison.OrdinalIgnoreCase) < 0)
                    continue;

                // force hint now, we only need to do this on one of the keys, not all
                table.PrimaryKey.Elements[0].SetAttribute("hint", CodeFluent.Producers.SqlServer.Constants.SqlServerProducerNamespaceUri, "clustered");

                // remember this table
                list.Add(table);
            }
            return list;
        }

        public static void RemoveClusteredHint(IEnumerable<Table> list)
        {
            foreach (var table in list)
            {
                table.PrimaryKey.Elements[0].RemoveAttribute("hint", CodeFluent.Producers.SqlServer.Constants.SqlServerProducerNamespaceUri);
            }
        }

        // helper method to read XML element's hint attribute in the SQL Server Producer namespace
        private static string GetSqlServerProducerHint(Node node)
        {
            if (node == null)
                return null;

            return node.GetAttributeValue<string>("hint", CodeFluent.Producers.SqlServer.Constants.SqlServerProducerNamespaceUri, null);
        }
    } 
    ?>

</cf:project>
于 2016-01-12T13:07:50.957 回答