How to update the sql server's identity column using play2.6 slick3? - sql-server

I got the following error when i try to run the sbt scala project using sql server,
[SQLServerException: Cannot update identity column 'ID'.]
I am using Play 2.6,Scala 2.12, Slick 3
my update function is,
def update(id: Long): Action[AnyContent] = Action.async { implicit request =>
topicForm.bindFromRequest.fold(
formWithErrors => Future.successful(BadRequest(html.editForm(id, formWithErrors))),
topic => {
val futureTopUpdate = dao.update(id, topic.copy(id = Some(id)))
futureTopUpdate.map { result =>
Home.flashing("success" -> "Topic %s has been updated".format(topic.code))
}.recover {
case ex: TimeoutException =>
Logger.error("Problem found in topic update process")
InternalServerError(ex.getMessage)
}
})
}
and the DAO:
override def update(id: Long, topic: Topic): Future[Int] =
try db.run(filterQuery(id).update(topic))
finally db.close
any idea?

You can show the filterQuery(id) implementation, something similar in a dao of us works well in this way:
override def update(id: Long, topic: Topic): Future[Int] = {
db.run(filterQuery(id).update(topic.copy(id))
}
Notice: topic.copy(id)
And filterQuery is:
def filterQuery(id: Int) = themes.filter(_.id === id)
We using Play 2.6,Scala 2.12, Slick 3 with MYSQL.
Update # 1:
-> Entity:
case class CategoryRow(id: Int, name: String, description: String)
-> Mapping:
trait CategoryMapping {
self: HasDatabaseConfigProvider[JdbcProfile] =>
import dbConfig.profile.api._
private[models] class CategoryTable(tag: Tag)
extends Table[CategoryRow](tag, "category") {
def id = column[Int]("id", O.AutoInc, O.PrimaryKey)
def name = column[String]("name", O.Length(TextMaxLength_250))
def description = column[String]("description", Nullable)
def categoryNameAgencyIndex = index("categoryName_agency_idx", (name, agencyId), unique = true)
override def * = (
id,
name,
description
) <> (CategoryRow.tupled, CategoryRow.unapply)
}
private[models] val Categories = TableQuery[CategoryTable]
private[models] val CategoriesInsertQuery = Categories returning Categories.map(_.id)
}
-> REPO
trait CategoryRepository {
//...
def update(id: Int, category: Category)(implicit agencyId: Int): Future[Int]
//...
}
-> REPOImpl:
#Singleton
class CategoryRepositoryImpl #Inject()(protected val dbConfigProvider: DatabaseConfigProvider)(implicit ec: RepositoryExecutionContext)
extends CategoryRepository with HasDatabaseConfigProvider[JdbcProfile] with CategoryMapping {
import dbConfig.profile.api._
//....
def update(id: Int, category: CategoryRow)(implicit agencyId: Int): Future[Int] =
db.run(filter(id).update(category.copy(id)))
private def filter(id: Int) = Categories.filter(_.id === id)
//....
}
-> RepositoryExecutionContex
class RepositoryExecutionContext #Inject()(actorSystem: ActorSystem) extends CustomExecutionContext(actorSystem, "repository.dispatcher")
and aplication.conf:
# db connections = ((physical_core_count * 2) + effective_spindle_count)
fixedConnectionPool = 5
repository.dispatcher {
executor = "thread-pool-executor"
throughput = 1
thread-pool-executor {
fixed-pool-size = ${fixedConnectionPool}
}
}
There's some more information about fold in Chapter 3.3 of Essential Slick.

Related

How to create entity related to a class, that derives from Table in Kotlin Exposed?

I'm trying to create entity for a table like this:
import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.Table
object TestTable: Table("tests") {
val id: Column<Long> = long("id").autoIncrement()
val name: Column<String> = varchar("name", 32)
override val primaryKey = PrimaryKey(id, name="pk_test_id")
}
class Test (id: EntityID<Long>): Entity<Long>(id) {
}
Something like this seems to work:
val testId = TestTable.insert {
it[name] = "test_name_1"
} get TestTable.id
Is it possible to create an entity and then insert it? Something, like this?:
val testEntity = Test()
...
db.insert(testEntity)
I'm not looking for a solution using IntTable, StringTable, ..., as in the exposed documentation. Just with a Table from exposed.
You can write insert method
object TestTable: LongIdTable("tests", columnName = "id") {
val name = varchar("name", 32)
}
class TestEntity (id: EntityID<Long>): LongEntity(id) {
companion object: LongEntityClass<TestEntity>(TestTable)
var name by TestTable.name
}
data class Result(
val id: Long,
val name:String
) {
companion object {
fun TestEntity.fromEntity(): Result = Result(
id = id.value,
name = name
)
fun fromRow(row: ResultRow) = Result(
id = row[TestTable.id].value,
name = row[TestTable.name]
)
}
}
fun insert(result: Result) = transaction {
return#transaction TestEntity.new {
this.name = result.name
}.fromEntity()
}
fun update(result: Result) = transaction {
return#transaction TestEntity.findById(result.id)?.apply {
this.name = result.name
}?.fromEntity()
}
fun firstSelect(name: String) = transaction {
return#transaction TestEntity.find {
TestTable.name eq name
}.map { it.fromEntity() }
}
fun secondSelect(name: String) = transaction {
return#transaction TestTable.select {
TestTable.name eq name
}.map { Result.fromRow(it) }
}

Gatling prevent concurrent requests for same customer

I want to performance test a recommender system.
It is important that the sequence of each product request for the same customer_id is respected as it influences the CPU load of the system under test.
How should I approach this? (This is what I have so far the exec does not work in the foreach)
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class MySimulation extends Simulation {
val baseUrl = "http://127.0.0.1:8080" // http://127.0.0.1:8080/recommend/144/9200000033418652/
val contentType = "application/json"
var realtime_feeder = Array(
Map("product_ids" -> List("9200000118431183", "9200000118431213", "9200000089631081"), "customer_id" -> "1"),
Map("product_ids" -> List("9200000121305523"), "customer_id" -> "2"),
Map("product_ids" -> List("9200000118431349", "9200000089631025"), "customer_id" -> "3"),
)
val httpConfiguration = http.baseUrl(baseUrl)
.acceptHeader(contentType)
.contentTypeHeader(contentType)
.shareConnections
.warmUp(baseUrl)
val productRequest = http("Recommend ${customer_id} ${product_id}")
.get("/recommend/${customer_id}/${product_id}")
val scn = scenario("scenario")
.feed(realtime_feeder)
.foreach(session => {
val product_ids = session("product_ids").as[List[String]]
val customer_id = session("customer_id").as[String]
for (product_id <- product_ids){
exec(productRequest, customer_id, product_id)
}
},
)
setUp(
scn.inject(
atOnceUsers(2)
).protocols(httpConfiguration))
}
Read the documentation first. You have serious misunderstanding of Gatling's programming model.
For knowing what to put into foreach, read Expression and EL.
foreach requires an Expression[Seq[Any]] and you can create one with the expression language (EL). by writing "${product_ids}". This will fetch the session attribute product_ids from the virtual users' session.
foreach("${product_ids}", "product_id") {
// Write your actions that use `product_id`.
// E.g. use EL to create a JSON
}
BTW, kudos to you for knowing how dynamic payloads are important to making a load test realistic.
Thanks George Leung for his suggestions. Here is my working end result.
import io.gatling.core.Predef.{exec, _}
import io.gatling.http.Predef._
import scala.concurrent.duration._
class MySimilation extends Simulation {
val baseUrl = "http://127.0.0.1:8080" // http://127.0.0.1:8080/recommend/144/9200000033418652/
val contentType = "application/json"
var realtime_feeder = Array(
Map("product_ids" -> List("9200000118431183", "9200000118431213", "9200000089631081"), "customer_id" -> "1"),
Map("product_ids" -> List("9200000121305523"), "customer_id" -> "2"),
Map("product_ids" -> List("9200000118431349", "9200000089631025"), "customer_id" -> "3"),
).random
val httpConfiguration = http.baseUrl(baseUrl)
.acceptHeader(contentType)
.contentTypeHeader(contentType)
.shareConnections
.warmUp(baseUrl)
val productRequest = http("/recommend/${customer_id}/${product_id}/")
.get("/recommend/${customer_id}/${product_id}/")
val scn = scenario("scenario")
.feed(realtime_feeder)
.foreach("${product_ids}", "product_id") {
exec(productRequest).pause(1 seconds, 2 seconds)
}
setUp(
scn.inject(
nothingFor(5.seconds),
constantUsersPerSec(5) during (1 minutes)
).protocols(httpConfiguration))
}

why? error: Cannot figure out how to save this field into database

I stuck with a fool issue
I have response from server
data class AddressResponse(
#SerializedName("message") val responseMessage: String,
#SerializedName("success") val success: Int,
#SerializedName("status") val status: Int,
#SerializedName("data") val data: Data
) {
data class Data(
#SerializedName("id") val addressId: Long,
#SerializedName("status") val status: Int?,
#TypeConverters( CommunicationPropertiesConverter::class )
#SerializedName("communication_properties") val communicationProperties: AddAddressRequest.CommunicationProperties?,
#SerializedName("more_information") val moreInformation: String?
) {
data class CommunicationProperties(
#SerializedName("par1") var par1: Boolean,
#SerializedName("par2") val par2: Boolean,
#SerializedName("par3") val par3: Boolean,
#SerializedName("par4") val par4: Boolean
)
}
}
I use room and I have entity class
#Entity(tableName = "db_address")
data class DbAddress(
#PrimaryKey #ColumnInfo(name = COLUMN_ID) val id: Long,
#ColumnInfo(name = COLUMN_STATUS) val status: Int?,
#TypeConverters(CommunicationPropertiesConverter::class)
#ColumnInfo(name = COLUMN_COMM_PROPS) val communicationProperties: AddressResponse.Data.CommunicationProperties,
#ColumnInfo(name = COLUMN_MORE_INFO) val moreInfo: String?
)
I have a convertor a set annotations #TypeConverters & #TypeConverter
class CommunicationPropertiesConverter {
private val gson = Gson()
#TypeConverter
fun toCommunicationProperties(mString: String?): AddressResponse.Data.CommunicationProperties {
if (mString.isNullOrEmpty())
return AddressResponse.Data.CommunicationProperties(par1 = false, par2 = false, par3 = false, par4 = false)
val listType = object : TypeToken<AddressResponse.Data.CommunicationProperties>(){}.type
return gson.fromJson(mString, listType)
}
#TypeConverter
fun fromCommunicationProperties(properties: AddressResponse.Data.CommunicationProperties?): String {
if (properties == null)
return "0000"
return gson.toJson(properties)
}
}
but I still get an error
error: Cannot figure out how to save this field into database. You can
consider adding a type converter for it
private final ... AddressResponse.Data.CommunicationProperties communicationProperties = null
but I added converter to and from "primitive" type
why? what did I forget?
I had a similar issue and what worked for me was annotating that field (that has the custom type) with #Embedded. In my case, I didn't even need type converters anymore.

Data Class Either Object or Array

I have a Kotlin data class that has an arg that can either be an Object or Array. Is there a way to de-serialize a string into this class and not care if not an Array but somehow get it into an array of one?
data class Game(var name:List<NameItem>)
data class NameItem(var title: String, var id: Int)
data can come back as both ways a single object or an array of objects( I have no control over the data as it is 3rd party data.
jsonString = "{"game":{"name":{"title":"GameName","id":22}}}"
jsonString = "{"game":{"name":[{"title":"GameName","id":22},{"title":"GameName2","id":23}]}}"
game: Game? = Gson().fromJson(jsonString Game::class.java)
You have to write a custom JsonDeserializer. Both or your class should have the same parent class. Then, write a custom JsonDeserializer for this specific type.
For example:
sealed class GameParent() {
data class Game(val name: String): GameParent()
data class GameList(val games: List<Game>): GameParent()
}
class GameDeserializer : JsonDeserializer<GameParent> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): GameParent {
with(json) {
if(isJsonObject) {
// parse as Game
}
if(isJsonArray) {
// parse as GameList
}
}
}
}
Then, in your GsonBuilder you have to register this custom JsonDeserializer:
gsonBuilder.registerTypeAdapter(GameParent::class.java, GameDeserializer());
Now, whenever your Gson expect GameParent will use registered deserializer.
my suggestions for solving your task
my solution if name is object, replace it with arrays
data class Game(var name:List<NameItem> )
data class NameItem(var title: String, var id: Int)
fun main(args: Array<String>) {
var json = "{\"game\":{\"name\":[{\"title\":\"game 1\",\"id\":1},{\"title\":\"game 2\",\"id\":2}]}}"
println(useJsonParser(json)) //Game(name=[NameItem(title=game 1, id=1), NameItem(title=game 2, id=2)])
json = "{\"game\":{\"name\":[{\"title\":\"game 1\",\"id\":1}]}}"
println(useJsonParser(json)) //Game(name=[NameItem(title=game 1, id=1), NameItem(title=game 2, id=2)])
json = "{\"game\":{\"name\":{\"title\":\"game 1\",\"id\":1}}}" // not array
println(useJsonParser(json)) //Game(name=[NameItem(title=game 1, id=1)])
}
version 1 -- created and registry adapter link #Cililing
fun useJsonParser(json: String): Game? {
val gson = GsonBuilder().registerTypeAdapter(Game::class.java, GameDeserializer()).create()
return gson.fromJson(json, Game::class.java)
}
class GameDeserializer : JsonDeserializer<Game?> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): Game? {
val gameJson = json!!.asJsonObject.get("game")
if (gameJson.isJsonObject) {
val jsonName = gameJson.asJsonObject["name"]
val list = if (jsonName.isJsonObject) {
arrayOf(Gson().fromJson(jsonName, NameItem::class.java))
} else {
val fromJson = Gson().fromJson(jsonName, Array<NameItem>::class.java)
fromJson
}.toList()
return Game(list)
}
return null
}
}
version 2 -- manipulating the response
fun useJsonParser(json:String):Game?{
val jsonObject = JsonParser().parse(json).asJsonObject.get("game")
if(jsonObject.asJsonObject["name"].isJsonObject){
val jsonName = jsonObject.asJsonObject["name"].asJsonObject
val array = JsonArray()
array.add(jsonName)
jsonObject.asJsonObject.add("name", array) // rewrite origin JSON
}
return Gson().fromJson(jsonObject, Game::class.java)
}
vesrion 3 -- add adapter TypeToken>()
fun useJsonParser(json: String): Game? {
val type = object : TypeToken<MutableList<NameItem>>() {}.type
val gson = GsonBuilder().registerTypeAdapter(type, NameItemDeserializer()).create()
return gson.fromJson(JsonParser().parse(json).asJsonObject.get("game"), Game::class.java)
}
class NameItemDeserializer : JsonDeserializer<List<NameItem>?> {
override fun deserialize(json: JsonElement, type: Type, context: JsonDeserializationContext?): List<NameItem>? {
with(json){
return if(isJsonObject){
arrayListOf(Gson().fromJson(this,NameItem::class.java))
}else{
Gson().fromJson(this,Array<NameItem>::class.java).toList()
}
}
}
}

How to return a type parameter that is a subtype of an Array?

I don't understand why this code is impossible in Scala:
def getColumns[T <: Array[_]] ():Array[(String,T)] ={
Array(Tuple2("test",Array(1.0,2.0,3.0)))
}
Compiler says:
Expression of type Array[(String,Array[Double])] doesn't conform to expected type Array[(String, T)]
I have the same error with this code:
def getColumns[T <: Array[Double]] ():Array[(String,T)] ={
Array(Tuple2("test",Array(1.0,2.0,3.0)))
}
It's more clear with my complete use case, finally I have chosen an Array[AnyVal]:
class SystemError(message: String, nestedException: Throwable) extends Exception(message, nestedException) {
def this() = this("", null)
def this(message: String) = this(message, null)
def this(nestedException : Throwable) = this("", nestedException)
}
class FileDataSource(path:String) {
val fileCatch = catching(classOf[FileNotFoundException], classOf[IOException]).withApply(e => throw new SystemError(e))
def getStream():Option[BufferedSource]={
fileCatch.opt{Source.fromInputStream(getClass.getResourceAsStream(path))}
}
}
class CSVReader(src:FileDataSource) {
def lines= src.getStream().get
val head = lines.getLines.take(1).toList(0).split(",")
val otherLines = lines.getLines.drop(1).toList
def getColumns():Array[(String,Array[_])] ={
val transposeLines = otherLines.map { l => l.split(",").map {
d => d match {
case String => d
case Int => d.toInt
case Double => d.toDouble
}}.transpose }
head zip transposeLines.map {_.toArray}
}
}
Can you give me some explanation or good links to understand the issues?
Because your function must be able to work with any T (any array type), however, it will always return an Array[(String,Array[Double])].
A simpler working signature would be:
def getColumns[T](): Array[(String,Array[T])]
But in the body of the function you will have to create an array of type T.
Your function signature requires a T in the compound return type, but you give it a Array[Double]. Note that T <: Array[Double], not the other way around. The following code works:
def getColumns[T >: Array[Double]] ():Array[(String,T)] ={
Array(Tuple2("test",Array(1.0,2.0,3.0)))
}
Shouldn't be what you want but just for elaborating the problem.

Resources