[PSQLException:错误:重复键值违反了唯一约束 “dictionary_word_idx”详细信息:Key(word)=(odirane)已经存在。]
我有唯一的索引可以防止任何重复。我想知道如何InsertAll一个包含数千个元素但只有新元素的数组?我正在使用Slick 1.0.1和Postgresql 9.1
修改 我正在尝试以下方法:
def run = {
val source = scala.io.Source.fromFile("/home/user/dev/txt/test1.txt")
val lines = source.mkString
source.close()
val words = lines.split("[^\\p{Ll}]").distinct
database withTransaction {
val q = for {
w <- words.toList
row <- Dictionary if row.word != w
} yield w
Dictionary.autoInc.insertAll(q: _*)
}
words.length
}
但是需要编译:
polymorphic expression cannot be instantiated to expected type;
[error] found : [G, T]scala.slick.lifted.Query[G,T]
[error] required: scala.collection.GenTraversableOnce[?] [error]
row <- Dictionary if row.word != w
编辑2:
case class Word(id: Option[Long], word:String)
object Dictionary extends Table[Word]("dictionary") {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def word = column[String]("word")
def * = id.? ~ word <> (Word, Word.unapply _)
def dictionary_word_idx = index("dictionary_word_idx", word, unique = true)
def autoInc = word returning id
}
答案 0 :(得分:2)
另一种方法是编写原始SQL。 Postgres没有on duplicate ignore
的默认方式,但您可以通过几种不同的方式模拟它,如https://dba.stackexchange.com/questions/30499/optimal-way-to-ignore-duplicate-inserts
将其与http://slick.typesafe.com/doc/1.0.0-RC2/sql.html
相结合编辑:
这是一个例子
def insert(c: String) =
(Q.u + """INSERT INTO dictionary
(word)
SELECT""" +? c +
"""WHERE
NOT EXISTS (
SELECT word FROM dictionary WHERE word = """ +? c + ")"
).execute
val words = lines.split("[^\\p{Ll}]")
words.foreach(insert)
这就是“立刻”的意思吗?我认为这将是最高效的方式,而不是疯狂。
如果它对你来说太慢了,还有另一个建议是创建一个没有唯一约束的临时表,将当前表复制到临时表中,将新单词插入临时表,然后从该表中选择不同的表。这显示在这里:https://stackoverflow.com/a/4070385/375874
但我觉得这样做太过分了。除非你有一些疯狂的要求或什么。
答案 1 :(得分:1)
概念:
def insertAll[T](items: Seq[T]): Seq[Either[(T, Exception), (T, Int)]] = items.map { i =>
try {
// Perform an insert supposing returns and int representing the PK on the table
val pk = …
Right(i, pk)
} catch {
case e: Exception => Left(i, e)
}
}
执行每个插入操作,然后根据结果返回一个Left或Right对象,该对象保留最终结果的轨迹,并为您提供详细的上下文来解释操作。
修改强>
让我们假设您的DAO对象如下:
object Dictionary extends Table[Word]("dictionary") {
// ...
}
其中Word
是你的对象模型,而且你已经提供了螺母和螺栓(我可以从你的粘贴代码中推断出来)它应该是(words
是Seq[Word]
) :
words.map { w =>
try {
Right(w, Dictionary.autoInc.insert(w))
} catch {
case e: Exception => Left(w, e)
}
}
你得到的是一系列Either
,它包含了进一步处理的结果。
<强>考虑强> 我提供的解决方案乐观地尝试对DB执行操作,而不需要根据DB的状态预先过滤列表。 通常,预过滤在大量多用户应用程序中存在问题,前提是您不能假设在执行过滤器后没有人在预过滤列表中添加单词。 陈述更简单:唯一性约束是DBMS提供的一个强大的功能,它比利用重新发明更好。 您上面编辑的解决方案是无解决方案,因为您仍然需要面对可能的PK违规异常。