3

NHibernateを使用してSQLiteデータベースに一括挿入する必要があります。オブジェクトのPKはHiLoint32です。session.insertでNHステートレスセッションを使用しようとしましたが、正常に動作します。ただし、preparedコマンドを使用すると約30〜40%高速であることがわかったので、それを利用しようとしています。

現在、ID(NH HiLo)の割り当てに苦労しています。stackoverflow(NHibernate HiLo ID Generator。保存する前にIDを生成する)の解決策を見つけました-メソッドGenerateIdentifier()を参照してください。ただし、呼び出しごとにデータベースを照会および更新するため、適切なオプションではありません。

想定どおりに機能させる方法はありますか?idジェネレーターがhivalueに達すると、サーバーへのラウンドトリップを1回だけ実行して、新しいlow値とhi値を取得しますか?

public static Int64 TestNHSQLiteBulk(bool newDB)
        {
            int ProjectCount = 1000000;

            var factory = Database.CreateSQLiteSessionFactory(newDB);

            Int64 objectCount = 0;

            using (var session = factory.OpenStatelessSession())
            {
                var connection = session.Connection;
                using (var transaction = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
                {

                    // this should be removed when proper HiLo will be implemented.
                    var nextProject = session.CreateCriteria<Project>().SetProjection(Projections.Max<Project>(p => p.ProjectId)).UniqueResult();
                    int startId = (nextProject == null) ? 0 : (int)nextProject + 1;

                    var command = connection.CreateCommand();
                    command.CommandText = "Insert INTO Project (ProjectId, ProjectName) Values(?,?)";

                    var projectIdParameter = command.CreateParameter();
                    projectIdParameter.ParameterName = "ProjectId";
                    projectIdParameter.DbType = System.Data.DbType.Int32;

                    var projectNameParameter = command.CreateParameter();
                    projectNameParameter.ParameterName = "ProjectName";
                    projectNameParameter.DbType = System.Data.DbType.String;

                    command.Parameters.Add(projectIdParameter);
                    command.Parameters.Add(projectNameParameter);
                    command.Prepare();

                    for (int p = startId; p < startId + ProjectCount; p++)
                    {

                        var project = new Project()
                        {
                            ProjectName = "Project " + p
                        };

                        //found on stackoverflow, but is results a roundtrip to server on each call.
                        GenerateIdentifier(project, Database.savedConfig, session);

                        //session.Insert(project);

                        //using prepared command is almost 2x faster!
                        projectIdParameter.Value = project.ProjectId;
                        projectNameParameter.Value = project.ProjectName;
                        command.ExecuteNonQuery();

                        objectCount++;
                    }

                    transaction.Commit();
                }

            }

            return objectCount;
        }

    //this will get the value and update the hi-lo value repository in the datastore
    public static void GenerateIdentifier(object target, NHibernate.Cfg.Configuration conf, IStatelessSession session)
    {
        var targetType = target.GetType();

        var classMapping = conf.GetClassMapping(targetType);
        var impl = session.GetSessionImplementation();

        var newId = classMapping.Identifier.CreateIdentifierGenerator(impl.Factory.Dialect, classMapping.Table.Catalog, classMapping.Table.Schema,
                                                                classMapping.RootClazz).Generate(impl, target);
        classMapping.IdentifierProperty.GetSetter(targetType).Set(target, newId);
    }
4

1 に答える 1

3

指定されたエンティティを使用する代わりに、エンティティごとに新しいHiLogeneratorを作成します。また、ジェネレータは通常、データベース内の値に初期化されるため、手動でクエリを実行する必要はありません。

public static Int64 TestNHSQLiteBulk(bool newDB)
{
    int ProjectCount = 1000000;

    var factory = Database.CreateSQLiteSessionFactory(newDB);

    var classMapping = (SingleTableEntityPersister)factory.GetClassMetadata(typeof(Project));
    var generator = classMapping.IdentifierGenerator;

    Int64 objectCount = 0;

    using (var session = factory.OpenStatelessSession())
    {
        var connection = session.Connection;
        using (var transaction = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
        {
            var command = connection.CreateCommand();
            command.CommandText = "Insert INTO Project (ProjectId, ProjectName) Values(?,?)";

            var projectIdParameter = command.CreateParameter();
            projectIdParameter.ParameterName = "ProjectId";
            projectIdParameter.DbType = System.Data.DbType.Int32;

            var projectNameParameter = command.CreateParameter();
            projectNameParameter.ParameterName = "ProjectName";
            projectNameParameter.DbType = System.Data.DbType.String;

            command.Parameters.Add(projectIdParameter);
            command.Parameters.Add(projectNameParameter);
            command.Prepare();

            for (int p = 0; p < ProjectCount; p++)
            {
                var projectId = (long)generator.Generate(session.GetSessionImplementation(), null);

                //using prepared command is almost 2x faster!
                projectIdParameter.Value = projectId;
                projectNameParameter.Value = "Project" + projectId;
                command.ExecuteNonQuery();

                objectCount++;
            }

            transaction.Commit();
        }
    }

    return objectCount;
}
于 2012-09-19T12:26:16.133 に答える