खैर, बहुत शोध और परस्पर विरोधी दस्तावेज़ीकरण की समीक्षा के बाद, मुझे इसका उत्तर मिल गया। दुर्भाग्य से, यह वह नहीं था जिसकी मुझे तलाश थी:
लब्बोलुआब यह है कि स्लिक बॉक्स से बाहर संग्रहीत कार्यों या प्रक्रियाओं का समर्थन नहीं करता है, इसलिए हमें अपना खुद का लिखना होगा।
उत्तर सत्र ऑब्जेक्ट को पकड़कर स्लिक से बाहर निकलना है, और फिर प्रक्रिया कॉल को प्रबंधित करने के लिए मानक जेडीबीसी का उपयोग करना है। आप में से जो JDBC से परिचित हैं, उनके लिए यह कोई खुशी की बात नहीं है... लेकिन, सौभाग्य से, स्काला के साथ हम पैटर्न मिलान के साथ कुछ बहुत अच्छी तरकीबें कर सकते हैं जो काम को आसान बनाती हैं।
मेरे लिए पहला कदम एक स्वच्छ बाहरी एपीआई को एक साथ रखना था। अंत में यह इस तरह दिख रहा था:
val db = Database.forDataSource(DB.getDataSource)
var response: Option[GPInviteResponse] = None
db.withSession {
implicit session => {
val parameters = GPProcedureParameterSet(
GPOut(Types.INTEGER) ::
GPIn(Option(i.token), Types.VARCHAR) ::
GPIn(recipientAccountId, Types.INTEGER) ::
GPIn(Option(contactType), Types.INTEGER) ::
GPIn(contactValue, Types.VARCHAR) ::
GPIn(None, Types.INTEGER) ::
GPIn(Option(requestType), Types.CHAR) ::
GPOut(Types.INTEGER) ::
Nil
)
val result = execute(session.conn, GPProcedure.SendInvitation, parameters)
val rc = result.head.asInstanceOf[Int]
Logger(s"FUNC return code: $rc")
response = rc match {
case 0 => Option(GPInviteResponse(true, None, None))
case _ => Option(GPInviteResponse(false, None, Option(GPError.errorForCode(rc))))
}
}
}
db.close()
यहां एक त्वरित पूर्वाभ्यास है:मैंने संग्रहीत प्रक्रिया कॉल को मॉडल करने के लिए एक साधारण कंटेनर बनाया है। GPProcedureParameterSet में GPIn, GPOut, या GPInOut इंस्टेंस की सूची हो सकती है। इनमें से प्रत्येक मानचित्र एक JDBC प्रकार के लिए एक मान है। कंटेनर इस तरह दिखता है:
case class GPOut(parameterType: Int) extends GPProcedureParameter
object GPOut
case class GPIn(value: Option[Any], parameterType: Int) extends GPProcedureParameter
object GPIn
case class GPInOut(value: Option[Any], parameterType: Int) extends GPProcedureParameter
object GPInOut
case class GPProcedureParameterSet(parameters: List[GPProcedureParameter])
object GPProcedureParameterSet
object GPProcedure extends Enumeration {
type GPProcedure = Value
val SendInvitation = Value("{?=call app_glimpulse_invitation_pkg.n_send_invitation(?, ?, ?, ?, ?, ?, ?)}")
}
पूर्णता के लिए मैं GPProcedure एन्यूमरेशन को शामिल कर रहा हूं ताकि आप इसे एक साथ रख सकें।
यह सब मेरे execute()
. को सौंप दिया जाता है समारोह। यह बड़ा और गंदा है, पुराने जमाने के JDBC की तरह खुशबू आ रही है, और मुझे यकीन है कि मैं स्काला में काफी सुधार करूंगा। मैंने इसे कल रात 3 बजे सचमुच समाप्त कर दिया ... लेकिन यह काम करता है, और यह वास्तव में अच्छी तरह से काम करता है। ध्यान दें कि यह विशेष execute()
फ़ंक्शन एक List
देता है सभी आउट पैरामीटर युक्त... मुझे एक अलग executeQuery()
write लिखना होगा एक प्रक्रिया को संभालने के लिए कार्य करता है जो resultSet
returns देता है . (हालांकि अंतर मामूली है:आप केवल एक लूप लिखते हैं जो resultSet.next
पकड़ लेता है और यह सब एक List
में भर दें या जो भी अन्य संरचना आप चाहते हैं)।
यहाँ बड़ा बुरा स्काला है<->JDBC मैपिंग execute()
समारोह:
def execute(connection: Connection, procedure: GPProcedure, ps: GPProcedureParameterSet) = {
val cs = connection.prepareCall(procedure.toString)
var index = 0
for (parameter <- ps.parameters) {
index = index + 1
parameter match {
// Handle any IN (or INOUT) types: If the optional value is None, set it to NULL, otherwise, map it according to
// the actual object value and type encoding:
case p: GPOut => cs.registerOutParameter(index, p.parameterType)
case GPIn(None, t) => cs.setNull(index, t)
case GPIn(v: Some[_], Types.NUMERIC | Types.DECIMAL) => cs.setBigDecimal(index, v.get.asInstanceOf[java.math.BigDecimal])
case GPIn(v: Some[_], Types.BIGINT) => cs.setLong(index, v.get.asInstanceOf[Long])
case GPIn(v: Some[_], Types.INTEGER) => cs.setInt(index, v.get.asInstanceOf[Int])
case GPIn(v: Some[_], Types.VARCHAR | Types.LONGVARCHAR) => cs.setString(index, v.get.asInstanceOf[String])
case GPIn(v: Some[_], Types.CHAR) => cs.setString(index, v.get.asInstanceOf[String].head.toString)
case GPInOut(None, t) => cs.setNull(index, t)
// Now handle all of the OUT (or INOUT) parameters, these we just need to set the return value type:
case GPInOut(v: Some[_], Types.NUMERIC) => {
cs.setBigDecimal(index, v.get.asInstanceOf[java.math.BigDecimal]); cs.registerOutParameter(index, Types.NUMERIC)
}
case GPInOut(v: Some[_], Types.DECIMAL) => {
cs.setBigDecimal(index, v.get.asInstanceOf[java.math.BigDecimal]); cs.registerOutParameter(index, Types.DECIMAL)
}
case GPInOut(v: Some[_], Types.BIGINT) => {
cs.setLong(index, v.get.asInstanceOf[Long]); cs.registerOutParameter(index, Types.BIGINT)
}
case GPInOut(v: Some[_], Types.INTEGER) => {
cs.setInt(index, v.get.asInstanceOf[Int]); cs.registerOutParameter(index, Types.INTEGER)
}
case GPInOut(v: Some[_], Types.VARCHAR) => {
cs.setString(index, v.get.asInstanceOf[String]); cs.registerOutParameter(index, Types.VARCHAR)
}
case GPInOut(v: Some[_], Types.LONGVARCHAR) => {
cs.setString(index, v.get.asInstanceOf[String]); cs.registerOutParameter(index, Types.LONGVARCHAR)
}
case GPInOut(v: Some[_], Types.CHAR) => {
cs.setString(index, v.get.asInstanceOf[String].head.toString); cs.registerOutParameter(index, Types.CHAR)
}
case _ => { Logger(s"Failed to match GPProcedureParameter in executeFunction (IN): index $index (${parameter.toString})") }
}
}
cs.execute()
// Now, step through each of the parameters, and get the corresponding result from the execute statement. If there is
// no result for the specified column (index), we'll basically end up getting a "nothing" back, which we strip out.
index = 0
val results: List[Any] = for (parameter <- ps.parameters) yield {
index = index + 1
parameter match {
case GPOut(Types.NUMERIC) | GPOut(Types.DECIMAL) => cs.getBigDecimal(index)
case GPOut(Types.BIGINT) => cs.getLong(index)
case GPOut(Types.INTEGER) => cs.getInt(index)
case GPOut(Types.VARCHAR | Types.LONGVARCHAR | Types.CHAR) => cs.getString(index)
case GPInOut(v: Some[_], Types.NUMERIC | Types.DECIMAL) => cs.getInt(index)
case GPInOut(v: Some[_], Types.BIGINT) => cs.getLong(index)
case GPInOut(v: Some[_], Types.INTEGER) => cs.getInt(index)
case GPInOut(v: Some[_], Types.VARCHAR | Types.LONGVARCHAR | Types.CHAR) => cs.getString(index)
case _ => {
Logger(s"Failed to match GPProcedureParameter in executeFunction (OUT): index $index (${parameter.toString})")
}
}
}
cs.close()
// Return the function return parameters (there should always be one, the caller will get a List with as many return
// parameters as we receive):
results.filter(_ != (()))
}