Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Đọc một ĐẾN TỪ MỘT CẤU TRÚC được trả về bởi một thủ tục được lưu trữ

Tạo các đối tượng triển khai java.sql.SQLData . Trong trường hợp này, hãy tạo TEnclosureTAnimal các lớp, cả hai đều triển khai SQLData .

Chỉ FYI, trong các phiên bản Oracle JDBC mới hơn, các loại như oracle .sql.ARRAY không được dùng nữa để ủng hộ java.sql các loại. Mặc dù tôi không chắc cách viết một mảng (được mô tả dưới đây) chỉ bằng cách sử dụng java.sql API.

Khi bạn triển khai readSQL() bạn đọc các trường theo thứ tự. Bạn nhận được java.sql.Array với sqlInput.readArray() . Vì vậy, TEnclosure.readSQL() sẽ trông giống như thế này.

@Override
public void readSQL(SQLInput sqlInput, String s) throws SQLException {
    id = sqlInput.readBigDecimal();
    name = sqlInput.readString();
    Array animals = sqlInput.readArray();
    // what to do here...
}

Lưu ý:readInt() cũng tồn tại, nhưng Oracle JDBC dường như luôn cung cấp BigDecimal cho NUMBER

Bạn sẽ nhận thấy rằng một số API như java.sql.Array có các phương thức lấy một loại bản đồ Map<String, Class<?>> Đây là ánh xạ các tên kiểu Oracle tới lớp Java tương ứng của chúng khi triển khai SQLData (ORAData cũng có thể hoạt động?).

Nếu bạn chỉ gọi Array.getArray() , bạn sẽ nhận được Struct các đối tượng trừ khi trình điều khiển JDBC biết về các ánh xạ kiểu của bạn thông qua Connection.setTypeMap(typeMap) . Tuy nhiên, việc đặt typeMap trên kết nối không hoạt động với tôi, vì vậy tôi sử dụng getArray(typeMap)

Tạo Map<String, Class<?>> typeMap của bạn ở đâu đó và thêm các mục nhập cho các loại của bạn:

typeMap.put("T_ENCLOSURE", TEnclosure.class);
typeMap.put("T_ANIMAL", TAnimal.class);

Trong một SQLData.readSQL() triển khai, gọi sqlInput.readArray().getArray(typeMap) , trả về Object[] nơi Object các mục nhập hoặc thuộc loại TAnimal .

Tất nhiên là mã để chuyển đổi thành List<TAnimal> tẻ nhạt, vì vậy chỉ cần sử dụng chức năng tiện ích này và điều chỉnh nó theo nhu cầu của bạn theo chính sách danh sách rỗng và trống:

/**
 * Constructs a list from the given SQL Array
 * Note: this needs to be static because it's called from SQLData classes.
 *
 * @param <T> SQLData implementing class
 * @param array Array containing objects of type T
 * @param typeClass Class reference used to cast T type
 * @return List<T> (empty if array=null)
 * @throws SQLException
 */
public static <T> List<T> listFromArray(Array array, Class<T> typeClass) throws SQLException {
    if (array == null) {
        return Collections.emptyList();
    }
    // Java does not allow casting Object[] to T[]
    final Object[] objectArray = (Object[]) array.getArray(getTypeMap());
    List<T> list = new ArrayList<>(objectArray.length);
    for (Object o : objectArray) {
        list.add(typeClass.cast(o));
    }
    return list;
}

Mảng viết

Việc tìm ra cách viết một mảng thật khó chịu, các API Oracle yêu cầu một Kết nối để tạo một Mảng, nhưng bạn không có một Kết nối rõ ràng trong ngữ cảnh của writeSQL(SQLOutput sqlOutput) . May mắn thay, blog này có một thủ thuật / hack để lấy OracleConnection , mà tôi đã sử dụng ở đây.

Khi bạn tạo một mảng với createOracleArray() bạn chỉ định loại danh sách (T_ARRAY_ANIMALS ) cho tên kiểu, KHÔNG PHẢI là kiểu đối tượng số ít.

Đây là một hàm chung để viết mảng. Trong trường hợp của bạn, listType sẽ là "T_ARRAY_ANIMALS" và bạn sẽ chuyển vào List<TAnimal>

/**
 * Write the list out as an Array
 *
 * @param sqlOutput SQLOutput to write array to
 * @param listType array type name (table of type)
 * @param list List of objects to write as an array
 * @param <T> Class implementing SQLData that corresponds to the type listType is a list of.
 * @throws SQLException
 * @throws ClassCastException if SQLOutput is not an OracleSQLOutput
 */
public static <T> void writeArrayFromList(SQLOutput sqlOutput, String listType, @Nullable List<T> list) throws SQLException {
    final OracleSQLOutput out = (OracleSQLOutput) sqlOutput;
    OracleConnection conn = (OracleConnection) out.getSTRUCT().getJavaSqlConnection();
    conn.setTypeMap(getTypeMap());  // not needed?
    if (list == null) {
        list = Collections.emptyList();
    }
    final Array array = conn.createOracleArray(listType, list.toArray());
    out.writeArray(array);
}

Ghi chú:

  • Có lúc tôi nghĩ setTypeMap là bắt buộc, nhưng bây giờ khi tôi xóa dòng đó, mã của tôi vẫn hoạt động, vì vậy tôi không chắc liệu nó có cần thiết hay không.
  • Tôi không chắc bạn nên viết null hay mảng trống, nhưng tôi cho rằng mảng trống thì đúng hơn.

Mẹo về các loại Oracle

  • Oracle viết hoa mọi thứ, vì vậy tất cả các tên loại phải là chữ hoa.
  • Bạn có thể cần chỉ định SCHEMA.TYPE_NAME nếu loại không có trong giản đồ mặc định của bạn.
  • Nhớ grant execute trên các loại nếu người dùng bạn đang kết nối không phải là chủ sở hữu.
    Nếu bạn thực thi trên gói nhưng không phải loại, getArray() sẽ đưa ra một ngoại lệ khi nó cố gắng tìm kiếm siêu dữ liệu loại.

Mùa xuân

Dành cho các nhà phát triển sử dụng Spring , bạn có thể muốn xem Spring Data JDBC Extensions , cung cấp SqlArrayValueSqlReturnArray , rất hữu ích để tạo SimpleJdbcCall cho một thủ tục nhận một mảng làm đối số hoặc trả về một mảng.

Chương 7.2.1 Đặt giá trị ARRAY bằng SqlArrayValue cho tham số IN giải thích cách gọi các thủ tục với các tham số mảng.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Quy trình lưu trữ cuộc gọi trong PHP-OCI với các tham số

  2. Cách nhận hai giá trị trả về từ Quy trình lưu trữ của Oracle

  3. Làm thế nào để kiểm tra xem tất cả các trường có phải là duy nhất trong Oracle không?

  4. Độ dài tối đa của tên bảng trong Oracle là bao nhiêu?

  5. Làm thế nào để đặt tên bảng oracle không phân biệt chữ hoa chữ thường?