[seasar-dotnet:698] Re: Oracle にて Insert 文でシーケンスを使った ID の生成について

koyak [E-MAIL ADDRESS DELETED]
2007年 12月 16日 (日) 03:32:02 JST


近藤様

小谷です。

詳細なご連絡ありがとうございます。

S2Container.NET 1.3.5からInsert時にnullの列をinsert文に含まないようにする
修正を行っているのですが、この修正が原因と思われます。
大変申し訳ありません。

解決方法についてですが、
Seasar.Dao.Impl.InsertAutoDynamicCommandのIsTargetPropertyを
以下のように書き換えてみていただけないでしょうか。

protected override bool IsTargetProperty(IPropertyType pt, string
timestampPropertyName, string versionNoPropertyName, object bean)
{
    IIdentifierGenerator identifierGenerator = BeanMetaData.IdentifierGenerator;
    if (pt.IsPrimaryKey)
    {
        return identifierGenerator.IsSelfGenerate;
    }
    return base.IsTargetProperty(pt, timestampPropertyName,
versionNoPropertyName, bean);
}

元のコードではRDBMSのIDENTITYを使用している列をi
nsert文に含めないようにしています。
(insert時に自動的にRDBMSの方でIDが割り振られるため)

シーケンスの場合はIDENTITYと違いinsert文に列を含める必要があるのですが
これを含める処理が抜けていました。

こちらの環境で検証ができ次第修正したソースをコミットしたいと思います。
ご迷惑をおかけしました。

--------------------------------------------------------
koyak
mail:[E-MAIL ADDRESS DELETED]
--------------------------------------------------------



07/12/15 に Atsushi   Kondou<[E-MAIL ADDRESS DELETED]> さんは書きました:
> いつもお世話になっております。
> 近藤です。
>
> この度、S2Container.NET 1.3.0で稼動していたシステムをS2Container.NET 1.3.5にバージョンをあげたところ
> INSERT文が失敗するようになりました。
>
> Insert文でシーケンスを使ったIDの生成の際IDが無視されたSQLが生成されるようです
>
> 自分なりに調査をした結果を報告します。
> 解決策がお分かりでしたらをご教授下さい。
> よろしくお願いします。
>
>
> 環境:
> OS:Windows Vista
> DB:Oracle10g
> IDE:Visual Studio 2005 SP1
> 言語:C#
>
>
> Entityクラスの抜粋
> [Table("COMPANIES"), TimestampProperty("UpdateDate")]
> public class Company {
> /*Company.cs*/
>   [Column("ID"), ID(IDType.SEQUENCE, "COMPANIES_ID_SEQ",KindOfDbms.Oracle)]
>   public long? Id{
>     ・・・
>   }
>   public long? Code{
>     ・・・
>   }
>   public String Name{
>     ・・・
>   }
>   public DateTime UpdateDate{
>     ・・・
>   }
> }
> DAOクラスの抜粋
> [Bean(typeof(Company))]
> public interface ICompanyDao {
>   void Insert(Company company);
> }
>
> 1)生成されたSQL文でIDが対象となっていないので
>   INSERT INTO COMPANIES (UPDATE_DATE, NAME, CODE) VALUES (?, ?, ?)
> が実行され以下の例外が発生する
> [ESSR0071]SQLで例外が発生しました。理由はSystem.Data.OracleClient.OracleException: ORA-01400:
> ("HOGE"."COMPANIES"."ID")
> にはNULLは挿入できません。
>    場所 System.Data.OracleClient.OracleConnection.CheckError(OciErrorHandle errorHandle, Int32 rc)
>    場所 System.Data.OracleClient.OracleCommand.Execute(OciStatementHandle statementHandle,
> CommandBehavior behavior, Boolean needRowid, OciRowidDescriptor& rowidDescriptor, ArrayList&
> resultParameterOrdinals)
>    場所 System.Data.OracleClient.OracleCommand.ExecuteNonQueryInternal(Boolean needRowid,
> OciRowidDescriptor& rowidDescriptor)
>    場所 System.Data.OracleClient.OracleCommand.ExecuteNonQuery()
>    場所 Seasar.Framework.Util.CommandUtil.ExecuteNonQuery(IDataSource dataSource, IDbCommand cmd) 場
> 所 E:\csharp\s2container.net\source\Seasar\Seasar.Framework.Util\CommandUtil.cs:行 66
>
> 2)SetIdentifierではシーケンスを使ってIDは生成されるのを確認しました。
>
> 3)この箇所が原因みたいなのですがどう解釈すれば良いのかわかりません。
> Seasar.Dao.Impl::AbstractAutoDynamicCommandのCreateTargetPropertyTypes
> Seasar.Dao.Impl::InsertAutoDynamicCommand
> Seasar.Dao.Impl::AbstractAutoDynamicCommandのIsTargetProperty
> object value = pt.PropertyInfo.GetValue(bean, null);
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ここでIDの場合valueがnullなのでfalseが返る
> if(value == null)
> {
>     return false;
> }
>
> 4)Seasar.Dao.Impl::AbstractAutoHandlerで_bindVariablesのインスタンス変数でIDが対象外になっている
> Execute
>   PreUpdateBean(bean);←beanのIDには生成されたIDが含まれている
>   SetupBindVariables(bean);
>   └Seasar.Dao.Impl::InsertAutoHandler::SetupBindVariables
>       SetupInsertBindVariables(bean);
>       └インスタンス変数の_propertyTypesにはIDが除かれている
>
> 以上
> _______________________________________________
> seasar-dotnet mailing list
> [E-MAIL ADDRESS DELETED]
> https://ml.seasar.org/mailman/listinfo/seasar-dotnet
>


seasar-dotnet メーリングリストの案内