zoukankan      html  css  js  c++  java
  • 修改EFOracleProvider——让EFOracleProvider支持自增长类型

    我们知道Oracle不像SqlServer那样,支持原生的自动增长型,而是通过sequence来实现类似于自增长类型的效果。

    对于以项目为主的公司而言,往往需要做到数据库之间的切换。而当初引入Entity Framework,一个重要的目标就是不同数据库之间的快速切换。

    现在面临的一个问题就是:自增长类型,如果做到不用修改代码,就能支持无缝切换

    说句题外话,关于主键类型的选择

    1. 自增长类型

    优:简单、查找方便、空间占用少

    缺:不同类型数据库的支持不同、数据同步

    2. Guid 的string

    优:数据同步较方便

    缺:占用空间大——一般用32个字符,查找不便——没有先后次序规律

    3. 自定义的生成规则

    嗯,不管你们用什么类型的主键,反正我是需要改造一下EFOracleProvider来支持如下的功能

    var entity = new XX();
    //去掉设置主键值
    //entity.ID = 20;
    entity.Column1 = something;

    //dbContext.Add(entity);

    在动手前,我们需要先约定以下规则:

    1. 所有表的主键名称统一叫ID

    2. 为每个表建立一个序列(sequence),规则是 SEQ_表名(序列的名字长度不能超过30个字符,所以表名不要超过26个字符)

    完成该功能,需要修改以下3个文件(共4处地方)

    1. Resources\EFOracleStoreSchemaDefinition.ssdl 

    2. SqlGen\DmlSqlGenerator.cs 

    3. SqlGen\SqlGenerator.cs 

    1. 修改 EFOracleStoreSchemaDefinition.ssdl

    定位到第36行,将

              , 0                     "IsIdentity"

    修改为:

              , case c.COLUMN_NAME when 'ID' then 1 else 0 end                     "IsIdentity" 

    目的在于,告诉生成工具(edmgen2,网上搜) ,如果是ID字段,在edmx文件中,加入

    <Property Name="ID" Type="number" Nullable="false" Precision="10" />

    变成 

    <Property Name="ID" Type="number" Nullable="false" Precision="10" StoreGeneratedPattern="Identity" />

    2. 修改insert语句的生成规则,在DmlSqlGenerator.cs文件中,找到GenerateInsertSql方法,然后用如下代码替换

    GenerateInsertSql
            internal static string GenerateInsertSql(DbInsertCommandTree tree, EFOracleProviderManifest providerManifest, EFOracleVersion sqlVersion, out List<OracleParameter> parameters)
            {
                StringBuilder commandText = new StringBuilder(s_commandTextBuilderInitialCapacity);
                ExpressionTranslator translator = new ExpressionTranslator(commandText, tree,
                    null != tree.Returning, sqlVersion);

                // insert [schemaName].[tableName]
                commandText.Append("insert into ");
                tree.Target.Expression.Accept(translator);
                if (0 < tree.SetClauses.Count)
                {
                    // (c1, c2, c3, ...)
                    commandText.Append("(");
                    bool first = true;
                    var dbNewInstanceExpression = tree.Returning as DbNewInstanceExpression;//自增长ID,zhb added
                    bool hasAutoIdentity = dbNewInstanceExpression != null && dbNewInstanceExpression.Arguments.Count > 0;
                    if (hasAutoIdentity)
                    {
                        first = false;
                        dbNewInstanceExpression.Arguments[0].Accept(translator);
                    }
                    foreach (DbSetClause setClause in tree.SetClauses)
                    {
                        if (first) { first = false; }
                        else { commandText.Append(""); }
                        setClause.Property.Accept(translator);
                    }
                    commandText.AppendLine(")");

                    // values c1, c2, ...
                    first = true;
                    commandText.Append("values (");
                    if (hasAutoIdentity)
                    {
                        translator.Sequence(tree.Target.Expression as DbScanExpression);
                        first = false;
                    }
                    foreach (DbSetClause setClause in tree.SetClauses)
                    {
                        if (first) { first = false; }
                        else { commandText.Append(""); }
                        setClause.Value.Accept(translator);

                        translator.RegisterMemberValue(setClause.Property, setClause.Value);
                    }
                    commandText.AppendLine(")");
                }
                else
                {
                    // default values
                    commandText.AppendLine().AppendLine("default values");
                }
                // generate returning sql
                GenerateReturningSql(commandText, tree, translator, tree.Returning, providerManifest, sqlVersion);

                parameters = translator.Parameters;
                return commandText.ToString();

     这段代码的作用在于,将原本

    insert into t(column1) values('value1') 

    变成

    insert into t(id, column1) values(seq_t.nextval, 'value1') 

    3. 由于我们在第2步时,调用了

    translator.Sequence(tree.Target.Expression as DbScanExpression);

    所以我们需要修改一下ExpressionTranslator 类(在DmlSqlGenerator.cs文件中),为其添加一个Sequece的方法,如下

                internal void Sequence(DbScanExpression scanExpression)
                {
                    _commandText.Append(SqlGenerator.GetSequenceSql(scanExpression.Target));

                }

    4. 由于第3步,sequence的生成,又转到了SqlGenerator类中,于是我们在SqlGenerator.cs中,添加GetSequenceSql方法

    GetSequenceSql
    internal static string GetSequenceSql(EntitySetBase entitySetBase)
            {
                // ##ORACLE
                
    // CONSIDER caching generated SQL here

                string definingQuery = MetadataHelpers.GetMetadataProperty<string>(entitySetBase,
                    MetadataHelpers.DefiningQueryMetadata);

                if (true)
                {
                    // construct escaped T-SQL referencing entity set
                    StringBuilder builder = new StringBuilder(50);


                    string table = MetadataHelpers.GetMetadataProperty<string>(entitySetBase,
                        MetadataHelpers.TableMetadata);

                    if (!string.IsNullOrEmpty(table))
                    {
                        builder.Append("seq_" + table);
                    }
                    else
                    {
                        builder.Append("seq_" + entitySetBase.Name);
                    }
                    builder.Append(".nextval");
                    return builder.ToString();
                }


    至此,修改代码工作算是完成了,编译重新发布吧 

  • 相关阅读:
    小技巧
    常用的交互设计软件
    Android studio 使用SVN需要忽略的文件
    android studio 使用SVN 锁定文件,防止别人修改(基于Android studio 1.4 )
    git 和 github 关系?
    Double 数据保留两位小数一:五舍六入
    设计模式
    Java中关于日期类那些方法
    ios 开源免费接口
    华为招聘机试整理5:简单四则运算
  • 原文地址:https://www.cnblogs.com/binblog/p/2309785.html
Copyright © 2011-2022 走看看