/// <summary>
        /// Creates a new instance of CassandraRoleStore that will use the provided ISession instance to talk to Cassandra.  Optionally,
        /// specify whether the ISession instance should be Disposed when this class is Disposed.
        /// </summary>
        /// <param name="session">The session for talking to the Cassandra keyspace.</param>
        /// <param name="disposeOfSession">Whether to dispose of the session instance when this object is disposed.</param>
        /// <param name="createSchema">Whether to create the schema tables if they don't exist.</param>
        public RoleStore(ISession session, bool disposeOfSession = false, bool createSchema = true)
        {
            _session          = session;
            _disposeOfSession = disposeOfSession;

            // Create some reusable prepared statements so we pay the cost of preparing once, then bind multiple times
            _createRoleByname = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync(
                                                                      "INSERT INTO Roles_by_name (name, id, description) " +
                                                                      "VALUES (?, ?, ?)"));

            _deleteRoleByname = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync("DELETE FROM Roles_by_name WHERE name = ?"));

            // All the statements needed by the CreateAsync method
            _createRole = new AsyncLazy <PreparedStatement[]>(() => Task.WhenAll(new []
            {
                _session.PrepareAsync("INSERT INTO Roles (id, name, description) " +
                                      "VALUES (?, ?, ?)"),
                _createRoleByname.Value,
            }));

            // All the statements needed by the DeleteAsync method
            _deleteRole = new AsyncLazy <PreparedStatement[]>(() => Task.WhenAll(new[]
            {
                _session.PrepareAsync("DELETE FROM Roles WHERE id = ?"),
                _deleteRoleByname.Value,
            }));

            // All the statements needed by the UpdateAsync method
            _updateRole = new AsyncLazy <PreparedStatement[]>(() => Task.WhenAll(new []
            {
                _session.PrepareAsync("UPDATE Roles SET name = ?, description = ? " +
                                      "WHERE id = ?"),
                _session.PrepareAsync("UPDATE Roles_by_name SET description = ? " +
                                      "WHERE name = ?"),
                _deleteRoleByname.Value,
                _createRoleByname.Value,
            }));

            _findById   = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync("SELECT * FROM Roles WHERE id = ?"));
            _findByName = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync("SELECT * FROM Roles_by_name WHERE name = ?"));

            // Create the schema if necessary
            if (createSchema)
            {
                SchemaCreationHelper.CreateSchemaIfNotExists(session);
            }
        }
        /// <summary>
        /// Creates a new instance of CassandraUserStore that will use the provided ISession instance to talk to Cassandra.  Optionally,
        /// specify whether the ISession instance should be Disposed when this class is Disposed.
        /// </summary>
        /// <param name="session">The session for talking to the Cassandra keyspace.</param>
        /// <param name="disposeOfSession">Whether to dispose of the session instance when this object is disposed.</param>
        /// <param name="createSchema">Whether to create the schema tables if they don't exist.</param>
        public UserStore(ISession session, bool disposeOfSession = false, bool createSchema = true)
        {
            _session          = session;
            _disposeOfSession = disposeOfSession;

            // Create some reusable prepared statements so we pay the cost of preparing once, then bind multiple times
            _createUserByUserName = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync(
                                                                          "INSERT INTO users_by_username (username, id, password_hash, security_stamp, two_factor_enabled, access_failed_count, " +
                                                                          "lockout_enabled, lockout_end_date, phone_number, phone_number_confirmed, email, email_confirmed) " +
                                                                          "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
            _createUserByEmail = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync(
                                                                       "INSERT INTO users_by_email (email, id, username, password_hash, security_stamp, two_factor_enabled, access_failed_count, " +
                                                                       "lockout_enabled, lockout_end_date, phone_number, phone_number_confirmed, email_confirmed) " +
                                                                       "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));

            _deleteUserByUserName = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync("DELETE FROM users_by_username WHERE username = ?"));
            _deleteUserByEmail    = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync("DELETE FROM users_by_email WHERE email = ?"));

            // All the statements needed by the CreateAsync method
            _createUser = new AsyncLazy <PreparedStatement[]>(() => Task.WhenAll(new []
            {
                _session.PrepareAsync("INSERT INTO users (id, username, password_hash, security_stamp, two_factor_enabled, access_failed_count, " +
                                      "lockout_enabled, lockout_end_date, phone_number, phone_number_confirmed, email, email_confirmed) " +
                                      "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),
                _createUserByUserName.Value,
                _createUserByEmail.Value
            }));

            // All the statements needed by the DeleteAsync method
            _deleteUser = new AsyncLazy <PreparedStatement[]>(() => Task.WhenAll(new[]
            {
                _session.PrepareAsync("DELETE FROM users WHERE id = ?"),
                _deleteUserByUserName.Value,
                _deleteUserByEmail.Value
            }));

            // All the statements needed by the UpdateAsync method
            _updateUser = new AsyncLazy <PreparedStatement[]>(() => Task.WhenAll(new []
            {
                _session.PrepareAsync("UPDATE users SET username = ?, password_hash = ?, security_stamp = ?, two_factor_enabled = ?, access_failed_count = ?, " +
                                      "lockout_enabled = ?, lockout_end_date = ?, phone_number = ?, phone_number_confirmed = ?, email = ?, email_confirmed = ? " +
                                      "WHERE id = ?"),
                _session.PrepareAsync("UPDATE users_by_username SET password_hash = ?, security_stamp = ?, two_factor_enabled = ?, access_failed_count = ?, " +
                                      "lockout_enabled = ?, lockout_end_date = ?, phone_number = ?, phone_number_confirmed = ?, email = ?, email_confirmed = ? " +
                                      "WHERE username = ?"),
                _deleteUserByUserName.Value,
                _createUserByUserName.Value,
                _session.PrepareAsync("UPDATE users_by_email SET username = ?, password_hash = ?, security_stamp = ?, two_factor_enabled = ?, access_failed_count = ?, " +
                                      "lockout_enabled = ?, lockout_end_date = ?, phone_number = ?, phone_number_confirmed = ?, email_confirmed = ? " +
                                      "WHERE email = ?"),
                _deleteUserByEmail.Value,
                _createUserByEmail.Value
            }));

            _findById    = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync("SELECT * FROM users WHERE id = ?"));
            _findByName  = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync("SELECT * FROM users_by_username WHERE username = ?"));
            _findByEmail = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync("SELECT * FROM users_by_email WHERE email = ?"));

            _addLogin = new AsyncLazy <PreparedStatement[]>(() => Task.WhenAll(new []
            {
                _session.PrepareAsync("INSERT INTO logins (id, login_provider, provider_key) VALUES (?, ?, ?)"),
                _session.PrepareAsync("INSERT INTO logins_by_provider (login_provider, provider_key, id) VALUES (?, ?, ?)")
            }));
            _removeLogin = new AsyncLazy <PreparedStatement[]>(() => Task.WhenAll(new []
            {
                _session.PrepareAsync("DELETE FROM logins WHERE id = ? and login_provider = ? and provider_key = ?"),
                _session.PrepareAsync("DELETE FROM logins_by_provider WHERE login_provider = ? AND provider_key = ?")
            }));
            _getLogins           = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync("SELECT * FROM logins WHERE id = ?"));
            _getLoginsByProvider = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync(
                                                                         "SELECT * FROM logins_by_provider WHERE login_provider = ? AND provider_key = ?"));

            _getClaims = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync("SELECT * FROM claims WHERE id = ?"));
            _addClaim  = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync(
                                                               "INSERT INTO claims (id, type, value) VALUES (?, ?, ?)"));
            _removeClaim = new AsyncLazy <PreparedStatement>(() => _session.PrepareAsync(
                                                                 "DELETE FROM claims WHERE id = ? AND type = ? AND value = ?"));

            // Create the schema if necessary
            if (createSchema)
            {
                SchemaCreationHelper.CreateSchemaIfNotExists(session);
            }
        }