{"id":369138,"date":"2024-05-21T03:57:04","date_gmt":"2024-05-21T03:57:04","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=369138"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=369138","title":{"rendered":"<span>\u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b N+1 \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 Kotlin Exposed<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435<\/h2>\n<p>\u041a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u043f\u043e\u0434\u043e\u0448\u0451\u043b \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Kotlin Exposed \u0432 \u0440\u0430\u0431\u043e\u0447\u0438\u0445, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445, \u043a\u043e\u0433\u0434\u0430 \u044f \u043d\u0430\u0447\u0430\u043b \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0435 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u0412 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u044f \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0441\u044f \u0441 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439 N+1)<\/p>\n<p>\u0421\u0443\u0442\u044c \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 ORM \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 N SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0434\u043b\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u0432\u043c\u0435\u0441\u0442\u043e \u043e\u0434\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0449\u0435\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<p>\u0427\u0442\u043e \u0441\u0430\u043c\u043e\u0435 \u0433\u043b\u0430\u0432\u043d\u043e\u0435, \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u044f \u043d\u0430\u0448\u0451\u043b \u043b\u0438\u0448\u044c \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u0411\u043b\u0430\u0433\u043e Kotlin Exposed \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u043e \u043c\u043d\u0435 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u0438\u0439\u0442\u0438 \u043a \u0440\u0435\u0448\u0435\u043d\u0438\u044e.<\/p>\n<h2>\u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430<\/h2>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0441\u0431\u043e\u0440\u043a\u0438 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f Gradle \u0441 Kotlin \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u044f\u0437\u044b\u043a\u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432. \u041d\u0430\u0447\u043d\u0451\u043c \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0444\u0430\u0439\u043b <code>build.gradle.kts<\/code><\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f Exposed \u0432 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439:<\/p>\n<pre><code class=\"kotlin\">dependencies {   implementation(\"org.jetbrains.exposed:exposed-core:$exposedVersion\")   implementation(\"org.jetbrains.exposed:exposed-jdbc:$exposedVersion\")   implementation(\"org.jetbrains.exposed:exposed-dao:$exposedVersion\") }<\/code><\/pre>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 \u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u0430\u044f H2, \u0438\u043c\u0435\u044e\u0449\u0430\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438, \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 <a href=\"https:\/\/www.h2database.com\/html\/features.html\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>:<\/p>\n<pre><code class=\"kotlin\">dependencies {   testImplementation(\"com.h2database:h2:$h2Version\") }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0437\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0435\u0439 SQL \u0432 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0431\u0443\u0434\u0443\u0442 \u0442\u0435\u0441\u0442\u044b, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 JUnit:<\/p>\n<pre><code class=\"kotlin\">tasks.test {   useJUnitPlatform() }<\/code><\/pre>\n<h2>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445<\/h2>\n<p> \u0414\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 Kotlin Exposed \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0434\u0432\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430:<\/p>\n<ol>\n<li>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 <code>javax.sql.DataSource<\/code><\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <code>url<\/code> \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a (\u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f, \u043b\u043e\u0433\u0438\u043d\/\u043f\u0430\u0440\u043e\u043b\u044c), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c <code>java.sql.DriverManager<\/code><\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u0441\u0440\u0435\u0434\u043d\u0435-\u043a\u0440\u0443\u043f\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442, \u043d\u043e \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u0438 \u0432\u0442\u043e\u0440\u043e\u0439, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043b\u0438\u0448\u043d\u0438\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u0441\u044f \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<pre><code class=\"kotlin\">Database.connect(   \/* mem \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0411\u0414 \u0432 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438 *\/   url = \"jdbc:h2:mem:airport;DB_CLOSE_DELAY=-1\",   driver = \"org.h2.Driver\", )<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438, \u043e\u043d\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u043e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f. \u0427\u0442\u043e\u0431\u044b \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u0430 \u0432\u043f\u043b\u043e\u0442\u044c \u0434\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>DB_CLOSE_DELAY=-1<\/code> \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 <code>url<\/code> \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438.<\/p>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438, \u0442\u0430\u043a \u0447\u0442\u043e \u043e\u0431\u044a\u044f\u0432\u0438\u043c top-level \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e<\/p>\n<pre><code class=\"kotlin\">fun &lt;T> loggedTransaction(statement: Transaction.() -> T) =   transaction {       addLogger(StdOutSqlLogger)       statement()   }<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043c\u044b \u043d\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0441\u0441\u044b\u043b\u043e\u043a \u043d\u0430 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0432 <code>Database.connect<\/code> \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0435<code>TransactionManager<\/code><\/p>\n<p>\u0414\u043b\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0445 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u0432\u044b\u0432\u043e\u0434\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>addLogger(StdOutSqlLogger)<\/code><\/p>\n<p>\u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u0441\u044f <a href=\"https:\/\/github.com\/JetBrains\/Exposed\/wiki\/Database-and-DataSource\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a><\/p>\n<h2>\u041f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u0430\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u044c<\/h2>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u044f \u0440\u0435\u0448\u0438\u043b \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0430\u044d\u0440\u043e\u043f\u043e\u0440\u0442, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0441\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0430\u0432\u0438\u0430\u0440\u0435\u0439\u0441\u043e\u0432. <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438:<\/p>\n<pre><code class=\"kotlin\">class Flight(     private val airplane: Airplane,     private val toAirport: Airport, ) {     override fun toString(): String = \"\u0420\u0435\u0439\u0441 \u043d\u0430 [$airplane] \u0432 [$toAirport]\" }  class Airplane(     private val yearReleased: Int,     private val firm: String,     private val model: String, ) {     override fun toString(): String = \"\u0421\u0430\u043c\u043e\u043b\u0451\u0442 $firm $model $yearReleased \u0433\u043e\u0434\u0430 \u0432\u044b\u043f\u0443\u0441\u043a\u0430\" }  class Airport(     private val country: String,     private val city: String,     private val iataCode: String, ) {     override fun toString(): String = \"\u0410\u044d\u0440\u043e\u043f\u043e\u0440\u0442 \u0432 \u043d.\u043f. $city, $country ($iataCode)\" }<\/code><\/pre>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0432\u044b\u0448\u0435\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u0441\u0441\u044b\u043b\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u0434\u0440\u0443\u0433 \u043d\u0430 \u0434\u0440\u0443\u0433\u0430:<\/p>\n<pre><code class=\"kotlin\">object FlightTable : IntIdTable(\"flights\") {     val airplane = reference(\"airplane_id\", AirplaneTable, onDelete = ReferenceOption.CASCADE)     val toAirport = reference(\"to_airport_id\", AirportTable, onDelete = ReferenceOption.CASCADE) }  object AirportTable : IntIdTable(\"airports\") {     val iataCode = varchar(\"iata_code\", 32)     val country = varchar(\"country\", 128)     val city = varchar(\"city\", 128) }  object AirplaneTable : IntIdTable(\"airplanes\") {     val firm = varchar(\"firm\", 128)     val yearReleased = integer(\"year_released\")     val model = varchar(\"model\", 128) }<\/code><\/pre>\n<p>\u0410 \u0442\u0430\u043a\u0436\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438. \u0415\u0441\u043b\u0438 \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435\u043c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e <a href=\"https:\/\/github.com\/JetBrains\/Exposed\/wiki\/DAO#referencing\" rel=\"noopener noreferrer nofollow\">\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f<\/a><\/p>\n<pre><code class=\"kotlin\">class FlightEntity(id: EntityID&lt;Int>) : IntEntity(id) {     companion object : IntEntityClass&lt;FlightEntity>(FlightTable)      val airplane by AirplaneEntity referencedOn FlightTable.airplane     val toAirport by AirportEntity referencedOn FlightTable.toAirport      fun toFlight(): Flight = Flight(         airplane = airplane.toAirplane(),         toAirport = toAirport.toAirport()     ) }  class AirplaneEntity(id: EntityID&lt;Int>): IntEntity(id) {     companion object : IntEntityClass&lt;AirplaneEntity>(AirplaneTable)      val yearReleased by AirplaneTable.yearReleased     val firm by AirplaneTable.firm     val model by AirplaneTable.model      fun toAirplane() = Airplane(yearReleased, firm, model) }  class AirportEntity(id: EntityID&lt;Int>) : IntEntity(id) {     companion object : IntEntityClass&lt;AirportEntity>(AirportTable)      val country by AirportTable.country     val city by AirportTable.city     val iataCode by AirportTable.iataCode      fun toAirport() = Airport(country, city, iataCode) }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438: ER-\u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0441\u0445\u0435\u043c\u044b \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2c7\/877\/330\/2c7877330e5ed9bfa30b55aff8022429.png\" alt=\"ER-\u0434\u0438\u0430\u0433\u0440\u0430\u043c\u0430\" title=\"ER-\u0434\u0438\u0430\u0433\u0440\u0430\u043c\u0430\" width=\"1013\" height=\"450\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2c7\/877\/330\/2c7877330e5ed9bfa30b55aff8022429.png\"\/><\/p>\n<div><figcaption>ER-\u0434\u0438\u0430\u0433\u0440\u0430\u043c\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u043f\u043e\u043b\u043d\u0438\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438:<\/p>\n<pre><code class=\"kotlin\">\/* 1 *\/ val airportID1 = AirportTable.insertAndGetId {     it[iataCode] = \"LED\"     it[country] = \"Russia\"     it[city] = \"St.Petersburg\" } val planeID1 = AirplaneTable.insertAndGetId {     it[yearReleased] = 2015     it[firm] = \"Airbus\"     it[model] = \"A320\" } FlightTable.insert {     it[toAirport] = airportID1     it[airplane] = planeID1 }  \/* 2 *\/ val airportID2 = AirportTable.insertAndGetId {     it[iataCode] = \"VKO\"     it[country] = \"Russia\"     it[city] = \"Moscow\" } val planeID2 = AirplaneTable.insertAndGetId {     it[yearReleased] = 2008     it[firm] = \"Boeing\"     it[model] = \"747\" } FlightTable.insert {     it[toAirport] = airportID2     it[airplane] = planeID2 }  \/* 3 *\/ val airportID3 = AirportTable.insertAndGetId {     it[iataCode] = \"DME\"     it[country] = \"Russia\"     it[city] = \"Moscow\" } val planeID3 = AirplaneTable.insertAndGetId {     it[yearReleased] = 2008     it[firm] = \"Sukhoi\"     it[model] = \"Superjet 100\" } FlightTable.insert {     it[toAirport] = airportID3     it[airplane] = planeID3 }<\/code><\/pre>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0432\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c: <strong>\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u0439\u0442\u0438 \u0432\u0441\u0435 \u0440\u0435\u0439\u0441\u044b, \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0435\u0441\u044f \u0432 \u0441\u0442\u0440\u0430\u043d\u0443 \u0420\u043e\u0441\u0441\u0438\u044f \u043d\u0430 \u0441\u0430\u043c\u043e\u043b\u0451\u0442\u0430\u0445, \u0432\u044b\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0445 \u043d\u0435 \u043f\u043e\u0437\u0436\u0435 2011 \u0433\u043e\u0434\u0430.<\/strong><\/p>\n<pre><code class=\"kotlin\">interface FlightRepository {        fun getFlightsToCountryByAirplaneYoungerThan(       destinationCountry: String,        youngerThanYear: Int     ): List&lt;Flight> }<\/code><\/pre>\n<p>\u0418\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0434\u043b\u044f \u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a<br \/>\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c. \u0422\u0430\u043a \u0447\u0442\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c<\/p>\n<h2>\u041d\u0430\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/h2>\n<p>\u0418\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u044f\u0441\u043d\u043e, \u0447\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0434\u0432\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<ol>\n<li>\n<p>DSL \u2013 \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u0430\u044f SQL-\u043f\u043e\u0434\u043e\u0431\u043d\u0430\u044f \u043e\u0431\u0451\u0440\u0442\u043a\u0430<\/p>\n<\/li>\n<li>\n<p>DAO \u2013 ORM-\u043e\u0431\u0451\u0440\u0442\u043a\u0430<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 N+1 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0435\u043d\u043d\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u0443 \u0441 ORM, \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Exposed DAO<\/p>\n<p>\u0418\u0437 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043f\u043e\u0438\u0441\u043a\u0430 \u0443 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 <code>Entity<\/code> \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0442\u043e\u0434\u043e\u0432:<\/p>\n<ul>\n<li>\n<p><code>get<\/code> \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043f\u043e ID \u0438\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0442\u0430\u043a\u043e\u0432\u043e\u0439<\/p>\n<\/li>\n<li>\n<p><code>findById<\/code> \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043f\u043e ID \u0438\u043b\u0438 <code>null<\/code> \u043f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0442\u0430\u043a\u043e\u0432\u043e\u0439<\/p>\n<\/li>\n<li>\n<p><code>find<\/code> \u0434\u043b\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u0430, \u043d\u043e \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>SqlExpressionBuilder<\/code><\/p>\n<\/li>\n<li>\n<p><code>all<\/code> \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"kotlin\">class PlainDaoFlightRepository : FlightRepository {      override fun getFlightsToCountryByAirplaneYoungerThan(         destinationCountry: String,         youngerThanYear: Int     ): List&lt;Flight> =         loggedTransaction {             FlightEntity.find {                 \/* AirportTable.country.lowerCase() eq destinationCountry.lowercase()                  and (AirplaneTable.yearReleased less youngerThanYear) *\/                 Op.nullOp()             }              FlightEntity.all().filter { flightEntity ->                 val targetCityMatches = flightEntity.toAirport.country.equals(destinationCountry, ignoreCase = true)                 val isYoungerThanYear = flightEntity.airplane.yearReleased &lt;= youngerThanYear                  targetCityMatches &amp;&amp; isYoungerThanYear              }.map(FlightEntity::toFlight)         }      override fun toString(): String = \"\u041d\u0430\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0447\u0435\u0440\u0435\u0437 Exposed DAO\" }<\/code><\/pre>\n<p>\u041f\u0440\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>find<\/code> \u0441 \u0443\u0441\u043b\u043e\u0432\u0438\u0435\u043c, \u0441\u0441\u044b\u043b\u0430\u044e\u0449\u0438\u043c\u0441\u044f \u043d\u0430 \u0432\u043d\u0435\u0448\u043d\u044e\u044e \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u0432\u044b\u043b\u0435\u0442\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"kotlin\">org.jetbrains.exposed.exceptions.ExposedSQLException:  org.h2.jdbc.JdbcSQLSyntaxErrorException: \u0421\u0442\u043e\u043b\u0431\u0435\u0446 \"AIRPORTS.COUNTRY\" \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d <\/code><\/pre>\n<p>\u0412\u0441\u0451 \u0434\u0435\u043b\u043e\u00a0\u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u00a0\u043f\u043e\u00a0\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 <code>SqlExpressionBuilder<\/code> \u0435\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u00a0\u0441\u0442\u043e\u043b\u0431\u0446\u0430\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u043d\u0430\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>find<\/code><\/p>\n<p>\u041f\u043e\u043a\u0430 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>all<\/code> \u0438 \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a\u00a0\u0440\u0435\u0448\u0435\u043d\u0438\u044e \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043f\u043e\u0437\u0436\u0435<\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0432 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0435\u0439 \u0432\u0441\u0435\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043b\u0438\u0441\u0442\u0438\u043d\u0433 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432:<\/p>\n<pre><code class=\"sql\">SQL: SELECT FLIGHTS.ID, FLIGHTS.AIRPLANE_ID, FLIGHTS.TO_AIRPORT_ID FROM FLIGHTS SQL: SELECT AIRPORTS.ID, AIRPORTS.IATA_CODE, AIRPORTS.COUNTRY, AIRPORTS.CITY FROM AIRPORTS WHERE AIRPORTS.ID = 1 SQL: SELECT AIRPLANES.ID, AIRPLANES.FIRM, AIRPLANES.YEAR_RELEASED, AIRPLANES.MODEL FROM AIRPLANES WHERE AIRPLANES.ID = 1 SQL: SELECT AIRPORTS.ID, AIRPORTS.IATA_CODE, AIRPORTS.COUNTRY, AIRPORTS.CITY FROM AIRPORTS WHERE AIRPORTS.ID = 2 SQL: SELECT AIRPLANES.ID, AIRPLANES.FIRM, AIRPLANES.YEAR_RELEASED, AIRPLANES.MODEL FROM AIRPLANES WHERE AIRPLANES.ID = 2 SQL: SELECT AIRPORTS.ID, AIRPORTS.IATA_CODE, AIRPORTS.COUNTRY, AIRPORTS.CITY FROM AIRPORTS WHERE AIRPORTS.ID = 3 SQL: SELECT AIRPLANES.ID, AIRPLANES.FIRM, AIRPLANES.YEAR_RELEASED, AIRPLANES.MODEL FROM AIRPLANES WHERE AIRPLANES.ID = 3<\/code><\/pre>\n<p>\u0422\u0438\u043f\u0438\u0447\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 N+1, \u043a\u043e\u0433\u0434\u0430 N \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u043b\u0435\u043d\u0438\u0432\u043e \u043f\u043e \u043c\u0435\u0440\u0435 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a \u043d\u0438\u043c.<\/p>\n<p>\u041d\u043e, \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0431\u044b, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u044e\u0442 \u0432 \u044d\u0442\u043e\u043c \u0441\u043f\u0438\u0441\u043a\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0438\u0445 \u043d\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0430 \u0441\u0440\u0430\u0437\u0443 \u043f\u0430\u0447\u043a\u043e\u0439.<\/p>\n<h2>\u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/h2>\n<p>\u0412 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0435\u0441\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 <a href=\"https:\/\/github.com\/JetBrains\/Exposed\/wiki\/DAO#eager-loading\" rel=\"noopener noreferrer nofollow\">\u0440\u0430\u0437\u0434\u0435\u043b<\/a><\/p>\n<p>\u0414\u043e\u043f\u0438\u0441\u0430\u0432, \u043a\u0430\u043a \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438, \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 <code>all<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"kotlin\">package com.strongmandrew.repository  import com.strongmandrew.domain.Flight import com.strongmandrew.entity.FlightEntity import com.strongmandrew.transaction.loggedTransaction import org.jetbrains.exposed.dao.with  class MediumDaoFlightRepository : FlightRepository {      override fun getFlightsToCountryByAirplaneYoungerThan(         destinationCountry: String,         youngerThanYear: Int     ): List&lt;Flight> =         loggedTransaction {             FlightEntity.all()             .with(FlightEntity::toAirport, FlightEntity::airplane) \/* !!! *\/             .filter { flightEntity ->                  val targetCityMatches = flightEntity.toAirport.country.equals(destinationCountry, ignoreCase = true)                 val isYoungerThanYear = flightEntity.airplane.yearReleased &lt;= youngerThanYear                  targetCityMatches &amp;&amp; isYoungerThanYear             }.map(FlightEntity::toFlight)         }      override fun toString(): String =         \"\u041d\u0430\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0441 Exposed DAO, \u043d\u043e \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u0441\u0432\u044f\u0437\u0430\u043d\u044b\u043c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c\" }<\/code><\/pre>\n<blockquote>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435: \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u0443\u044e (eager) \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u043d\u0430 \u0441\u043f\u0438\u0441\u043a\u0435 \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>with<\/code>, \u0442\u0430\u043a \u0438 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>load<\/code><\/p>\n<\/blockquote>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043c\u0435\u043d\u044c\u0448\u0435\u0435 \u043a\u043e\u043b-\u0432\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432:<\/p>\n<pre><code class=\"kotlin\">SQL: SELECT FLIGHTS.ID, FLIGHTS.AIRPLANE_ID, FLIGHTS.TO_AIRPORT_ID FROM FLIGHTS SQL: SELECT AIRPLANES.ID, AIRPLANES.FIRM, AIRPLANES.YEAR_RELEASED, AIRPLANES.MODEL FROM AIRPLANES WHERE AIRPLANES.ID IN (1, 2, 3) SQL: SELECT AIRPORTS.ID, AIRPORTS.IATA_CODE, AIRPORTS.COUNTRY, AIRPORTS.CITY FROM AIRPORTS WHERE AIRPORTS.ID IN (1, 2, 3) SQL: SELECT FLIGHTS.ID, FLIGHTS.AIRPLANE_ID, FLIGHTS.TO_AIRPORT_ID FROM FLIGHTS<\/code><\/pre>\n<p>\u041e\u0442\u043b\u0438\u0447\u043d\u043e, \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441\u0442\u0430\u043b\u043e \u043c\u0435\u043d\u044c\u0448\u0435, \u043d\u043e \u043f\u043e \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u0442\u0430\u0431\u043b\u0438\u0446\u0435 <code>FLIGHTS<\/code> \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u0441\u044f \u0434\u0432\u0430\u0436\u0434\u044b \u043d\u0430 1 \u0438 4 \u0441\u0442\u0440\u043e\u043a\u0430\u0445.<\/p>\n<p>\u0412 \u043f\u043e\u0438\u0441\u043a\u0430\u0445 \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0431\u0440\u0430\u0442\u0438\u043c\u0441\u044f \u043a \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u043c: \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 <code>all<\/code><\/p>\n<pre><code class=\"kotlin\">open fun all(): SizedIterable&lt;T> = wrapRows(table.selectAll().notForUpdate())<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 <code>Query<\/code> \u2013  \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 <code>selectAll<\/code> \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>wrapRows<\/code> <\/p>\n<p>\u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e \u0432\u044b\u0437\u043e\u0432 <code>selectAll<\/code> \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 SQL \u0437\u0430\u043f\u0440\u043e\u0441, \u0430 \u043b\u0438\u0448\u044c \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043e\u0431\u0451\u0440\u0442\u043a\u0443 \u0432 \u0432\u0438\u0434\u0435 <code>Query<\/code> \u0434\u043b\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430. \u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0434\u0430\u043b\u0435\u0435 \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <code>wrapRows<\/code><\/p>\n<pre><code class=\"kotlin\">fun wrapRows(rows: SizedIterable&lt;ResultRow>): SizedIterable&lt;T> = rows mapLazy {   wrapRow(it) }<\/code><\/pre>\n<p>\u0412\u0438\u0434\u0438\u043c \u043f\u0435\u0440\u0435\u0434 \u0441\u043e\u0431\u043e\u0439 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>mapLazy<\/code><\/p>\n<pre><code class=\"kotlin\">infix fun &lt;T, R> SizedIterable&lt;T>.mapLazy(f: (T) -> R): SizedIterable&lt;R> {     val source = this     return object : SizedIterable&lt;R> {         override fun limit(n: Int, offset: Long): SizedIterable&lt;R> = source.copy().limit(n, offset).mapLazy(f)         override fun forUpdate(option: ForUpdateOption): SizedIterable&lt;R> = source.copy().forUpdate(option).mapLazy(f)         override fun notForUpdate(): SizedIterable&lt;R> = source.copy().notForUpdate().mapLazy(f)         override fun count(): Long = source.count()         override fun empty(): Boolean = source.empty()         override fun copy(): SizedIterable&lt;R> = source.copy().mapLazy(f)         override fun orderBy(vararg order: Pair&lt;Expression&lt;*>, SortOrder>) = source.orderBy(*order).mapLazy(f)          @Suppress(\"IteratorNotThrowingNoSuchElementException\")         override operator fun iterator(): Iterator&lt;R> {             val sourceIterator = source.iterator()             return object : Iterator&lt;R> {                 override operator fun next(): R = f(sourceIterator.next())                  override fun hasNext(): Boolean = sourceIterator.hasNext()             }         }     } }<\/code><\/pre>\n<p>\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u0447\u0442\u043e \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440 \u043f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043a \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u0443 \u0440\u0435\u0441\u0438\u0432\u0435\u0440\u0430 <code>mapLazy<\/code>, \u043a\u043e\u0438\u043c \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 <code>Query<\/code>, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 <code>selectAll<\/code><\/p>\n<p>\u0417\u043d\u0430\u0447\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u044d\u0442\u0430\u043f\u043e\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u043a\u0430\u043a <code>Query<\/code> \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0441\u0432\u043e\u0439 \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440.<\/p>\n<pre><code class=\"kotlin\">override fun iterator(): Iterator&lt;ResultRow> {   val resultIterator = ResultIterator(transaction.exec(queryToExecute)!!)   return if (transaction.db.supportsMultipleResultSets) {       resultIterator   } else {       Iterable { resultIterator }.toList().iterator()   } }<\/code><\/pre>\n<p>\u041a\u0430\u0436\u0435\u0442\u0441\u044f, \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043d\u0430\u0439\u0434\u0435\u043d\u0430: \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u0430 <code>Query<\/code> \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 2 \u0441\u0442\u0440\u043e\u043a\u0435.<\/p>\n<p>\u0418\u0442\u043e\u0433\u043e:<\/p>\n<ol>\n<li>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u0442\u0430\u0431\u043b\u0438\u0446\u0435 <code>FLIGHTS<\/code> \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0451\u043b \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 <code>with<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0441\u0432\u043e\u0435\u0433\u043e \u0442\u0435\u043b\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 <code>toList<\/code>, \u0432\u044b\u0437\u044b\u0432\u0430\u044f \u0442\u0435\u043c \u0441\u0430\u043c\u044b\u043c \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440 <code>Query<\/code> <\/p>\n<\/li>\n<li>\n<p>\u0412\u0442\u043e\u0440\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0451\u043b \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 <code>filter<\/code>, \u0442\u0430\u043a \u043a\u0430\u043a <code>with<\/code> \u0445\u043e\u0442\u044c \u0438 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0441\u043f\u0438\u0441\u043e\u043a, \u043d\u043e \u0434\u0430\u043b\u044c\u0448\u0435 \u0435\u0433\u043e \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u043e\u043f\u044f\u0442\u044c \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043a \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u0443 <code>Query<\/code><\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0439 <code>filter<\/code> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0443\u0436\u0435 \u043d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a. \u0418\u043c\u0435\u043d\u043d\u043e \u043f\u043e \u044d\u0442\u043e\u0439 \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u043d\u0430 \u0432\u044b\u0437\u043e\u0432\u0435 <code>map<\/code> \u043d\u0435 \u0431\u044b\u043b\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0442\u0440\u0435\u0442\u044c\u0435\u0433\u043e SQL \u0437\u0430\u043f\u0440\u043e\u0441\u0430: \u043e\u043d \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u0441\u044f \u0443\u0436\u0435 \u041d\u0415 \u043d\u0430 \u043b\u0435\u043d\u0438\u0432\u043e\u043c \u0441\u043f\u0438\u0441\u043a\u0435.<\/p>\n<\/li>\n<\/ol>\n<p>\u0414\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u0440\u0430\u0437\u0443 \u043d\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 <code>all<\/code> \u0432\u044b\u0437\u0432\u0430\u0442\u044c <code>toList<\/code>, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0443\u0436\u0435 \u0441 \u0433\u043e\u0442\u043e\u0432\u044b\u043c \u0441\u043f\u0438\u0441\u043a\u043e\u043c<\/p>\n<pre><code class=\"kotlin\">\/* ... *\/ FlightEntity.all().toList() \/* !!! *\/   .with(FlightEntity::toAirport, FlightEntity::airplane)   .filter { flightEntity ->      val targetCityMatches = flightEntity.toAirport.country.equals(destinationCountry, ignoreCase = true)     val isYoungerThanYear = flightEntity.airplane.yearReleased &lt; youngerThanYear      targetCityMatches &amp;&amp; isYoungerThanYear }.map(FlightEntity::toFlight) \/* ... *\/<\/code><\/pre>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u043d\u0430\u043c \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e SQL \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043e\u0433\u043b\u043e \u0431\u044b\u0442\u044c X, \u0433\u0434\u0435 X \u044d\u0442\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043d\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c \u043b\u0435\u043d\u0438\u0432\u043e\u043c \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u0435)   <\/p>\n<pre><code class=\"sql\">SQL: SELECT FLIGHTS.ID, FLIGHTS.AIRPLANE_ID, FLIGHTS.TO_AIRPORT_ID FROM FLIGHTS SQL: SELECT AIRPLANES.ID, AIRPLANES.FIRM, AIRPLANES.YEAR_RELEASED, AIRPLANES.MODEL FROM AIRPLANES WHERE AIRPLANES.ID IN (1, 2, 3) SQL: SELECT AIRPORTS.ID, AIRPORTS.IATA_CODE, AIRPORTS.COUNTRY, AIRPORTS.CITY FROM AIRPORTS WHERE AIRPORTS.ID IN (1, 2, 3)<\/code><\/pre>\n<h2>\u0421\u043e\u0432\u043c\u0435\u0449\u0435\u043d\u0438\u0435 DSL \u0438 DAO   <\/h2>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u043d\u0430\u044f \u0432\u044b\u0448\u0435 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 DAO \u0445\u043e\u0442\u044c \u0438 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u043b\u0430 \u043a\u043e\u043b-\u0432\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0445 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043d\u043e \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0435\u0449\u0451 \u0434\u0430\u043b\u0435\u043a\u043e \u043e\u0442 \u0438\u0434\u0435\u0430\u043b\u0430.<\/p>\n<p>\u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0447\u0442\u043e, \u0435\u0441\u043b\u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 3, \u043a\u0430\u043a \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0430, \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c, 3_000_000. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0436\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0435 \u0442\u0430\u043a\u0438\u043c \u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u043c \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u0438\u0445 \u0432\u0441\u0435 \u0440\u0430\u0437\u043e\u043c \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u043f\u0430\u043c\u044f\u0442\u0438: <code>with<\/code> \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0431\u044f \u043a\u044d\u0448\u0438\u0440\u0443\u0435\u0442 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u0438\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c\u0438 SQL, \u0438 \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a DSL \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0435\u0439 \u0432 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>wrapRow<\/code><\/p>\n<p>\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0430\u0431\u043b\u0438\u0446 \u0438 \u0432\u043c\u0435\u0441\u0442\u0435 \u0438\u0445 \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u0442\u044c \u0432 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0435 SQL \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u0441 JOIN, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432 Exposed DSL \u0432\u044b\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 <code>leftJoin<\/code>, <code>rightJoin<\/code>, <code>innerJoin<\/code> \u0438 \u043f\u0440. <\/p>\n<p>\u041f\u043e \u0441\u0443\u0442\u0438 \u043e\u043d\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u044e\u0442 <code>ColumnSet<\/code> \u2013 \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0430\u043b\u0435\u0435 \u0431\u0443\u0434\u0443\u0442 \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435, \u0430 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u043c\u0435\u043b\u043e \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c \u0432\u043d\u0443\u0442\u0440\u0438 <code>select<\/code> (\u0437\u0430\u043f\u043e\u043c\u043d\u0438\u043c, \u044d\u0442\u043e \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 DAO)<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043b\u0438\u0441\u0442\u0438\u043d\u0433 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u0441\u043e\u0432\u043c\u0435\u0449\u0430\u044e\u0449\u0435\u0433\u043e DSL \u0438 DAO \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"kotlin\">class MixedDaoDslFlightRepository : FlightRepository {      override fun getFlightsToCountryByAirplaneYoungerThan(         destinationCountry: String,         youngerThanYear: Int     ): List&lt;Flight> =         loggedTransaction {             FlightTable.innerJoin(AirportTable).innerJoin(AirplaneTable).selectAll().where {                 AirportTable.country.lowerCase() eq destinationCountry.lowercase()             }.andWhere {                 AirplaneTable.yearReleased lessEq youngerThanYear             }.map { row ->                 FlightEntity.wrapRow(row).toFlight()             }         }      override fun toString(): String =         \"\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 Exposed DAO \u0438 DSL, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043a\u044d\u0448\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438\" }<\/code><\/pre>\n<p>\u041d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u044f\u0441\u043d\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u0443 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432:<\/p>\n<pre><code class=\"kotlin\">SQL: SELECT FLIGHTS.ID, FLIGHTS.AIRPLANE_ID, FLIGHTS.TO_AIRPORT_ID, AIRPORTS.ID, AIRPORTS.IATA_CODE, AIRPORTS.COUNTRY, AIRPORTS.CITY, AIRPLANES.ID, AIRPLANES.FIRM, AIRPLANES.YEAR_RELEASED, AIRPLANES.MODEL FROM FLIGHTS INNER JOIN AIRPORTS ON AIRPORTS.ID = FLIGHTS.TO_AIRPORT_ID INNER JOIN AIRPLANES ON AIRPLANES.ID = FLIGHTS.AIRPLANE_ID WHERE (LOWER(AIRPORTS.COUNTRY) = 'russia') AND (AIRPLANES.YEAR_RELEASED &lt;= 2011) SQL: SELECT AIRPLANES.ID, AIRPLANES.FIRM, AIRPLANES.YEAR_RELEASED, AIRPLANES.MODEL FROM AIRPLANES WHERE AIRPLANES.ID = 2 SQL: SELECT AIRPORTS.ID, AIRPORTS.IATA_CODE, AIRPORTS.COUNTRY, AIRPORTS.CITY FROM AIRPORTS WHERE AIRPORTS.ID = 2 SQL: SELECT AIRPLANES.ID, AIRPLANES.FIRM, AIRPLANES.YEAR_RELEASED, AIRPLANES.MODEL FROM AIRPLANES WHERE AIRPLANES.ID = 3 SQL: SELECT AIRPORTS.ID, AIRPORTS.IATA_CODE, AIRPORTS.COUNTRY, AIRPORTS.CITY FROM AIRPORTS WHERE AIRPORTS.ID = 3<\/code><\/pre>\n<p>\u041a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0431\u044b, \u0432\u043d\u0443\u0442\u0440\u0438 <code>map<\/code> \u043c\u044b \u0438\u043c\u0435\u0435\u043c <code>ResultRow<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u044f \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0442\u0430\u0431\u043b\u0438\u0446. \u0417\u0430\u0447\u0435\u043c Exposed \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043a \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438?<\/p>\n<p>\u0412 \u043f\u043e\u0438\u0441\u043a\u0430\u0445 \u043e\u0442\u0432\u0435\u0442\u0430 \u0432\u043d\u043e\u0432\u044c \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c\u0443 \u043a\u043e\u0434\u0443: \u043d\u0430\u0447\u043d\u0451\u043c \u0441 \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 <code>FlightEntity<\/code> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0438\u043a\u043d\u0435\u043c <code>Ctrl + B<\/code> \u043f\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u043c\u0443 \u0441\u043b\u043e\u0432\u0443 <code>by<\/code><\/p>\n<pre><code class=\"kotlin\">operator fun &lt;REF : Comparable&lt;REF>, RID : Comparable&lt;RID>, T : Entity&lt;RID>> Reference&lt;REF, RID, T>.getValue(         o: Entity&lt;ID>,         desc: KProperty&lt;*>     ): T {         val outOfTransaction = TransactionManager.currentOrNull() == null         if (outOfTransaction &amp;&amp; reference in referenceCache) return getReferenceFromCache(reference)         return executeAsPartOfEntityLifecycle {             val refValue = reference.getValue(o, desc)             when {                 refValue is EntityID&lt;*> &amp;&amp; reference.referee&lt;REF>() == factory.table.id -> {                     factory.findById(refValue.value as RID).also {                         storeReferenceInCache(reference, it)                     }                 }                 else -> {                     \/\/ @formatter:off                     factory.findWithCacheCondition({                         reference.referee!!.getValue(this, desc) == refValue                     }) {                         reference.referee&lt;REF>()!! eq refValue                     }.singleOrNull()?.also {                         storeReferenceInCache(reference, it)                     }                     \/\/ @formatter:on                 }             } ?: error(\"Cannot find ${factory.table.tableName} WHERE id=$refValue\")         }     }<\/code><\/pre>\n<p>\u0412 \u043a\u043e\u0434\u0435 \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u043d\u0430 8 \u0441\u0442\u0440\u043e\u043a\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043d\u0435\u043a\u043e\u0433\u043e <code>refValue<\/code> \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>getValue<\/code><\/p>\n<pre><code class=\"kotlin\">operator fun &lt;T> Column&lt;T>.getValue(o: Entity&lt;ID>, desc: KProperty&lt;*>): T = lookup()<\/code><\/pre>\n<p>\u0414\u0430\u0436\u0435 \u043d\u0435 \u0437\u0430\u0433\u043b\u044f\u0434\u044b\u0432\u0430\u044f \u0434\u0430\u043b\u044c\u0448\u0435 \u0432\u043d\u0443\u0442\u0440\u044c <code>lookup<\/code> \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0440\u0435\u0441\u0438\u0432\u0435\u0440\u043e\u043c \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <code>Column<\/code> \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u043a\u0430\u0441\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043d\u0438\u043a\u0443\u0434\u0430 \u0434\u0430\u043b\u044c\u0448\u0435 \u043d\u0435 \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442.<\/p>\n<p>\u042d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0434\u043b\u044f \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0451 ID, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0434\u0430\u043b\u0435\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u043e\u0438\u0441\u043a<\/p>\n<p>\u0422\u0430\u043a \u0438 \u0435\u0441\u0442\u044c, \u043d\u0430 10 \u0441\u0442\u0440\u043e\u043a\u0435 \u043c\u044b \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043d\u0430 \u0442\u043e, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u043a\u043b\u044e\u0447\u043e\u043c \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043f\u043e\u0438\u0441\u043a\u043e\u043c. \u0417\u0430\u0433\u043b\u044f\u043d\u0435\u043c \u0432\u043d\u0443\u0442\u0440\u044c \u043f\u043e\u0438\u0441\u043a\u0430 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 <code>findById<\/code><\/p>\n<pre><code class=\"kotlin\">open fun findById(id: EntityID&lt;ID>): T? = testCache(id) ?: find { table.id eq id }.firstOrNull()<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c-\u0442\u043e \u0432\u0441\u0451 \u0432\u0441\u0442\u0430\u0451\u0442 \u043d\u0430 \u0441\u0432\u043e\u0438 \u043c\u0435\u0441\u0442\u0430. \u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u0438\u0449\u0435\u0442\u0441\u044f \u0432 \u043a\u044d\u0448\u0435. \u0412\u0441\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u043c, \u0447\u0442\u043e \u0434\u043b\u044f <code>FlightEntity<\/code> \u043c\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u0438 \u043c\u0435\u0442\u043e\u0434 <code>wrapRow<\/code><\/p>\n<p>\u0423\u0433\u043b\u0443\u0431\u0438\u0432\u0448\u0438\u0441\u044c \u0432 \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e, \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u043e\u043d\u0430 \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043a\u044d\u0448<\/p>\n<pre><code class=\"kotlin\">fun wrap(id: EntityID&lt;ID>, row: ResultRow?): T {         val transaction = TransactionManager.current()         return transaction.entityCache.find(this, id) ?: createInstance(id, row).also { new ->             new.klass = this             new.db = transaction.db             warmCache().store(this, new) \/* \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 *\/         }     }<\/code><\/pre>\n<p>\u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043c\u0435\u0448\u0430\u0435\u0442 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e <code>ResultRow<\/code><\/p>\n<pre><code class=\"kotlin\">\/* ... *\/ FlightTable.innerJoin(AirportTable).innerJoin(AirplaneTable).selectAll().where {   AirportTable.country.lowerCase() eq destinationCountry.lowercase() }.andWhere {   AirplaneTable.yearReleased lessEq youngerThanYear }.map { row ->   AirplaneEntity.wrapRow(row) \/* \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 *\/   AirportEntity.wrapRow(row) \/* \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 *\/   FlightEntity.wrapRow(row).toFlight() } \/* ... *\/<\/code><\/pre>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0432\u0441\u0435\u0445 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0435\u0439, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0435\u0441\u044c\u043c\u0430 \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u044f\u044e\u0449\u0438\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 \u0432\u0438\u0434\u0435 \u043e\u0434\u043d\u043e\u0433\u043e (!) \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/p>\n<pre><code class=\"sql\">SQL: SELECT FLIGHTS.ID, FLIGHTS.AIRPLANE_ID, FLIGHTS.TO_AIRPORT_ID, AIRPORTS.ID, AIRPORTS.IATA_CODE, AIRPORTS.COUNTRY, AIRPORTS.CITY, AIRPLANES.ID, AIRPLANES.FIRM, AIRPLANES.YEAR_RELEASED, AIRPLANES.MODEL FROM FLIGHTS INNER JOIN AIRPORTS ON AIRPORTS.ID = FLIGHTS.TO_AIRPORT_ID INNER JOIN AIRPLANES ON AIRPLANES.ID = FLIGHTS.AIRPLANE_ID WHERE (LOWER(AIRPORTS.COUNTRY) = 'russia') AND (AIRPLANES.YEAR_RELEASED &lt;= 2011)<\/code><\/pre>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u0441\u043c\u0435\u0448\u0430\u043b\u0438 \u0434\u0432\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u0430 DSL \u0438 DAO, \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 DAO, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043b\u0435\u0433\u043a\u043e \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0432 \u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438<\/p>\n<p><strong>P.S.<\/strong><\/p>\n<p>\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u043d\u0435 \u0432\u043e \u0432\u0441\u0435\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0432 <code>ResultRow<\/code> \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043f\u043e\u043b\u044f \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 <code>leftJoin<\/code> \u0438\u043b\u0438 <code>rightJoin<\/code><\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u0434 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430<\/p>\n<pre><code class=\"kotlin\">.map { row ->   if (row.getOrNull(AirplaneTable.id) != null) {     AirplaneEntity.wrapRow(row) \/* \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 *\/   }   AirportEntity.wrapRow(row) \/* \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 *\/   FlightEntity.wrapRow(row).toFlight() }<\/code><\/pre>\n<h2>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u0430\u0441\u0430\u0434\u043e\u043c<\/h2>\n<p>\u0414\u0443\u043c\u0430\u044e, \u0438\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0442\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u044e \u044d\u0442\u0443 \u0446\u0435\u043f\u043e\u0447\u043a\u0443 <code>innerJoin<\/code> \u043c\u043e\u0436\u043d\u043e \u0441\u043f\u0440\u044f\u0442\u0430\u0442\u044c \u0437\u0430 \u0444\u0430\u0441\u0430\u0434\u043e\u043c <code>Entity<\/code><\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u043d\u0430\u043c \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 <code>find<\/code><\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c\u0441\u044f, \u043f\u043e\u0447\u0435\u043c\u0443 \u0442\u0430\u043a \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e:<\/p>\n<pre><code class=\"kotlin\">fun find(op: Op&lt;Boolean>): SizedIterable&lt;T> {   warmCache()   return wrapRows(searchQuery(op)) }<\/code><\/pre>\n<p>\u0412 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0439 \u043d\u0430\u043c \u043c\u0435\u0442\u043e\u0434 <code>wrapRows<\/code> \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043c\u0435\u0442\u043e\u0434\u0430 <code>searchQuery<\/code><\/p>\n<pre><code class=\"kotlin\">open val dependsOnTables: ColumnSet get() = table open val dependsOnColumns: List&lt;Column&lt;out Any?>> get() = dependsOnTables.columns  open fun searchQuery(op: Op&lt;Boolean>): Query =   dependsOnTables.select(dependsOnColumns).where { op }.setForUpdateStatus()<\/code><\/pre>\n<p>\u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u0432\u0441\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u043b\u0430\u0441\u044c \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e <code>find<\/code> \u0438\u0449\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0430\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u043f\u043e\u0432\u0435\u0440\u0445 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 <code>Entity<\/code><\/p>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0438 <code>dependsOnTables<\/code> \u043c\u0435\u0442\u043e\u0434 <code>find<\/code> \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u0435\u0442 \u043f\u0430\u0434\u0430\u0442\u044c \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439, \u043d\u043e \u044d\u0442\u043e \u0435\u0449\u0451 \u043d\u0435 \u0432\u0441\u0451.<\/p>\n<pre><code class=\"kotlin\">class FlightEntity(id: EntityID&lt;Int>) : IntEntity(id) {      companion object : IntEntityClass&lt;FlightEntity>(FlightTable) {          override val dependsOnTables: ColumnSet =              FlightTable.innerJoin(AirplaneTable).innerJoin(AirportTable)     }      val airplane by AirplaneEntity referencedOn FlightTable.airplane     val toAirport by AirportEntity referencedOn FlightTable.toAirport      fun toFlight(): Flight = Flight(         airplane = airplane.toAirplane(),         toAirport = toAirport.toAirport()     ) }<\/code><\/pre>\n<p>\u0415\u0449\u0451 \u0434\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0438\u0437\u0431\u0430\u0432\u0438\u0432\u0448\u0438\u0441\u044c \u043e\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u043f\u043e\u0438\u0441\u043a\u0435 \u043f\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c, \u043c\u044b \u043d\u0435 \u0438\u0437\u0431\u0430\u0432\u0438\u043c\u0441\u044f \u043e\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b N+1, \u0442\u0430\u043a \u043a\u0430\u043a \u0432\u043d\u0443\u0442\u0440\u0438 <code>wrapRows<\/code> \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043b\u0435\u043d\u0438\u0432\u043e\u0435.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u0435\u0442\u043e\u0434 <code>find<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u043c, \u0435\u0433\u043e \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u0437\u043d\u0430\u0447\u0438\u0442 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0441\u0432\u043e\u044e \u0432\u0435\u0440\u0441\u0438\u044e <code>find<\/code> \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<pre><code class=\"kotlin\">open class EagerSearchEntityClass&lt;ID : Comparable&lt;ID>, out E : Entity&lt;ID>>(table: IdTable&lt;ID>) :     EntityClass&lt;ID, E>(table) {      fun eagerFind(         vararg foreignEntities: EntityClass&lt;*, *>,         op: SqlExpressionBuilder.() -> Op&lt;Boolean>,     ): SizedIterable&lt;E> {         warmCache()          val entitiesBySearch = searchQuery(SqlExpressionBuilder.op()).map { resultRow ->             foreignEntities.forEach { entity -> entity.wrapRow(resultRow) }             this.wrapRow(resultRow)         }          return SizedCollection(entitiesBySearch)     } }<\/code><\/pre>\n<p>\u0423\u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c\u0441\u044f \u043e\u0442 \u044d\u0442\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <code>FlightEntity<\/code> <\/p>\n<pre><code class=\"kotlin\">class FlightEntity(id: EntityID&lt;Int>) : IntEntity(id) {      companion object : EagerSearchEntityClass&lt;Int, FlightEntity>(FlightTable) {          override val dependsOnTables: ColumnSet =             FlightTable.innerJoin(AirplaneTable).innerJoin(AirportTable)     } \/* ... *\/<\/code><\/pre>\n<p>\u041d\u043e\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"kotlin\">class ImprovedDaoFlightRepository : FlightRepository {      override fun getFlightsToCountryByAirplaneYoungerThan(         destinationCountry: String,         youngerThanYear: Int     ): List&lt;Flight> = loggedTransaction {         FlightEntity.eagerFind(AirportEntity, AirplaneEntity) {             AirportTable.country.lowerCase() eq destinationCountry.lowercase() and (AirplaneTable.yearReleased lessEq youngerThanYear)         }.map(FlightEntity::toFlight)     }      override fun toString(): String =         \"\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u043c\u0438 \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438 \u043f\u043e\u0438\u0441\u043a\u0430 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u0432 Entity-\u043a\u043b\u0430\u0441\u0441\u0435\" }<\/code><\/pre>\n<p>\u0423\u0441\u043b\u043e\u0432\u0438\u044f, \u0441\u0441\u044b\u043b\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u043d\u0430 \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0435 \u0443\u043f\u0430\u0434\u0443\u0442 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>dependsOnTables<\/code> \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043e \u0432 <code>FlightEntity<\/code><\/p>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e \u044d\u0442\u043e\u0433\u043e, \u0432\u0441\u0435 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0435 \u0432 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u0445, \u0431\u0443\u0434\u0443\u0442 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u044b, \u0447\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b N+1.<\/p>\n<p>\u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432, \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0435 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u043b\u043e\u0441\u044c, \u0430 \u043a\u043e\u0434 \u0441\u0442\u0430\u043b \u0431\u043e\u043b\u0435\u0435 \u0447\u0438\u0442\u0430\u0435\u043c\u044b\u043c:<\/p>\n<pre><code class=\"kotlin\">SQL: SELECT FLIGHTS.ID, FLIGHTS.AIRPLANE_ID, FLIGHTS.TO_AIRPORT_ID, AIRPLANES.ID, AIRPLANES.FIRM, AIRPLANES.YEAR_RELEASED, AIRPLANES.MODEL, AIRPORTS.ID, AIRPORTS.IATA_CODE, AIRPORTS.COUNTRY, AIRPORTS.CITY FROM FLIGHTS INNER JOIN AIRPLANES ON AIRPLANES.ID = FLIGHTS.AIRPLANE_ID INNER JOIN AIRPORTS ON AIRPORTS.ID = FLIGHTS.TO_AIRPORT_ID WHERE (LOWER(AIRPORTS.COUNTRY) = 'russia') AND (AIRPLANES.YEAR_RELEASED &lt;= 2011)<\/code><\/pre>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u0443 \u0442\u0430\u043a\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0435\u0441\u0442\u044c \u043e\u0434\u043d\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430: \u043c\u044b \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c\u0441\u044f \u043a \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0443 <code>dependsOnTables<\/code> \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0442\u0438\u043f \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0449\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u043f\u044b JOIN.<\/p>\n<p>\u041f\u0440\u0438 \u0442\u0430\u043a\u043e\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u043c\u043e\u0436\u043d\u043e \u0432\u043d\u0435\u0441\u0442\u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 \u0442\u0438\u043f\u0430 <code>ColumnSet<\/code> \u0432 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 \u0432\u0438\u0434\u0435 <code>dependsOnTables<\/code><\/p>\n<p>\u041f\u0440\u0438 \u044d\u0442\u043e\u043c, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u043c <code>ResultRow<\/code><\/p>\n<pre><code class=\"kotlin\">open class EagerSearchEntityClass&lt;ID : Comparable&lt;ID>, out E : Entity&lt;ID>>(table: IdTable&lt;ID>) :     EntityClass&lt;ID, E>(table) {              fun eagerFind(         vararg foreignEntities: EntityClass&lt;*, *>,         columnSet: ColumnSet = dependsOnTables, \/* \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u044b\u0431\u043e\u0440\u043a\u0443 *\/         op: SqlExpressionBuilder.() -> Op&lt;Boolean>,     ): SizedIterable&lt;E> {         warmCache()          val entitiesBySearch = searchByColumnSet(columnSet, SqlExpressionBuilder.op()).map { resultRow ->             foreignEntities.forEach { entity ->                  \/* \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 *\/                 if (resultRow.getOrNull(entity.table.id) != null) {                     entity.wrapRow(resultRow)                  }             }             this.wrapRow(resultRow)         }          return SizedCollection(entitiesBySearch)     }      open fun searchByColumnSet(columnSet: ColumnSet, op: Op&lt;Boolean>): Query = columnSet.selectAll().where(op) }<\/code><\/pre>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u041f\u043e\u0434\u0432\u043e\u0434\u044f \u0438\u0442\u043e\u0433\u0438 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438, \u043c\u044b \u043a\u043e\u043f\u043d\u0443\u043b\u0438 \u0433\u043b\u0443\u0431\u0436\u0435 \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Kotlin Exposed \u0438 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0440\u0430\u0437 \u0443\u0431\u0435\u0434\u0438\u043b\u0438\u0441\u044c \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0432\u0441\u0451 \u0432\u0441\u0435\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e, \u0438 \u0434\u0430\u0436\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u0438\u0442\u044c \u043d\u0430 \u0432\u0441\u0435 \u0432\u0430\u0448\u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u044b. <\/p>\n<p>\u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u044d\u0442\u043e \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c.<\/p>\n<p>\u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u0430\u0448\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u043d\u0430 Kotlin Exposed \u0441\u0442\u0430\u043d\u0443\u0442 \u0435\u0449\u0451 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0435\u0435, \u0430 \u0432\u0430\u0448\u0438 \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044f \u0441 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u044b\u043c\u0438)<\/p>\n<p><strong>\u041e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u0438\u0437 \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u043e <\/strong><a href=\"https:\/\/github.com\/strongmandrew\/kotlin-exposed-n-plus-1\" rel=\"noopener noreferrer nofollow\"><strong>\u0441\u0441\u044b\u043b\u043a\u0435<\/strong><\/a><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/796017\/\"> https:\/\/habr.com\/ru\/articles\/796017\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435<\/h2>\n<p>\u041a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u043f\u043e\u0434\u043e\u0448\u0451\u043b \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Kotlin Exposed \u0432 \u0440\u0430\u0431\u043e\u0447\u0438\u0445, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445, \u043a\u043e\u0433\u0434\u0430 \u044f \u043d\u0430\u0447\u0430\u043b \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0435 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u0412 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u044f \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0441\u044f \u0441 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439 N+1)<\/p>\n<p>\u0421\u0443\u0442\u044c \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 ORM \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 N SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0434\u043b\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u0432\u043c\u0435\u0441\u0442\u043e \u043e\u0434\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0449\u0435\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<p>\u0427\u0442\u043e \u0441\u0430\u043c\u043e\u0435 \u0433\u043b\u0430\u0432\u043d\u043e\u0435, \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u044f \u043d\u0430\u0448\u0451\u043b \u043b\u0438\u0448\u044c \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u0411\u043b\u0430\u0433\u043e Kotlin Exposed \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u043e \u043c\u043d\u0435 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u0438\u0439\u0442\u0438 \u043a \u0440\u0435\u0448\u0435\u043d\u0438\u044e.<\/p>\n<h2>\u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430<\/h2>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0441\u0431\u043e\u0440\u043a\u0438 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f Gradle \u0441 Kotlin \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u044f\u0437\u044b\u043a\u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432. \u041d\u0430\u0447\u043d\u0451\u043c \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0444\u0430\u0439\u043b <code>build.gradle.kts<\/code><\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f Exposed \u0432 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439:<\/p>\n<pre><code class=\"kotlin\">dependencies {   implementation(\"org.jetbrains.exposed:exposed-core:$exposedVersion\")   implementation(\"org.jetbrains.exposed:exposed-jdbc:$exposedVersion\")   implementation(\"org.jetbrains.exposed:exposed-dao:$exposedVersion\") }<\/code><\/pre>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 \u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u0430\u044f H2, \u0438\u043c\u0435\u044e\u0449\u0430\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438, \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 <a href=\"https:\/\/www.h2database.com\/html\/features.html\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>:<\/p>\n<pre><code class=\"kotlin\">dependencies {   testImplementation(\"com.h2database:h2:$h2Version\") }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0437\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0435\u0439 SQL \u0432 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0431\u0443\u0434\u0443\u0442 \u0442\u0435\u0441\u0442\u044b, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 JUnit:<\/p>\n<pre><code class=\"kotlin\">tasks.test {   useJUnitPlatform() }<\/code><\/pre>\n<h2>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445<\/h2>\n<p> \u0414\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 Kotlin Exposed \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0434\u0432\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430:<\/p>\n<ol>\n<li>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 <code>javax.sql.DataSource<\/code><\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <code>url<\/code> \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a (\u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f, \u043b\u043e\u0433\u0438\u043d\/\u043f\u0430\u0440\u043e\u043b\u044c), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c <code>java.sql.DriverManager<\/code><\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u0441\u0440\u0435\u0434\u043d\u0435-\u043a\u0440\u0443\u043f\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442, \u043d\u043e \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u0438 \u0432\u0442\u043e\u0440\u043e\u0439, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043b\u0438\u0448\u043d\u0438\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u0441\u044f \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<pre><code class=\"kotlin\">Database.connect(   \/* mem \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0411\u0414 \u0432 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438 *\/   url = \"jdbc:h2:mem:airport;DB_CLOSE_DELAY=-1\",   driver = \"org.h2.Driver\", )<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438, \u043e\u043d\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u043e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f. \u0427\u0442\u043e\u0431\u044b \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u0430 \u0432\u043f\u043b\u043e\u0442\u044c \u0434\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>DB_CLOSE_DELAY=-1<\/code> \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 <code>url<\/code> \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438.<\/p>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438, \u0442\u0430\u043a \u0447\u0442\u043e \u043e\u0431\u044a\u044f\u0432\u0438\u043c top-level \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e<\/p>\n<pre><code class=\"kotlin\">fun &lt;T> loggedTransaction(statement: Transaction.() -> T) =   transaction {       addLogger(StdOutSqlLogger)       statement()   }<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043c\u044b \u043d\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0441\u0441\u044b\u043b\u043e\u043a \u043d\u0430 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0432 <code>Database.connect<\/code> \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0435<code>TransactionManager<\/code><\/p>\n<p>\u0414\u043b\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0445 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u0432\u044b\u0432\u043e\u0434\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>addLogger(StdOutSqlLogger)<\/code><\/p>\n<p>\u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u0441\u044f <a href=\"https:\/\/github.com\/JetBrains\/Exposed\/wiki\/Database-and-DataSource\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a><\/p>\n<h2>\u041f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u0430\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u044c<\/h2>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u044f \u0440\u0435\u0448\u0438\u043b \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0430\u044d\u0440\u043e\u043f\u043e\u0440\u0442, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0441\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0430\u0432\u0438\u0430\u0440\u0435\u0439\u0441\u043e\u0432. <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438:<\/p>\n<pre><code class=\"kotlin\">class Flight(     private val airplane: Airplane,     private val toAirport: Airport, ) {     override fun toString(): String = \"\u0420\u0435\u0439\u0441 \u043d\u0430 [$airplane] \u0432 [$toAirport]\" }  class Airplane(     private val yearReleased: Int,     private val firm: String,     private val model: String, ) {     override fun toString(): String = \"\u0421\u0430\u043c\u043e\u043b\u0451\u0442 $firm $model $yearReleased \u0433\u043e\u0434\u0430 \u0432\u044b\u043f\u0443\u0441\u043a\u0430\" }  class Airport(     private val country: String,     private val city: String,     private val iataCode: String, ) {     override fun toString(): String = \"\u0410\u044d\u0440\u043e\u043f\u043e\u0440\u0442 \u0432 \u043d.\u043f. $city, $country ($iataCode)\" }<\/code><\/pre>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0432\u044b\u0448\u0435\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u0441\u0441\u044b\u043b\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u0434\u0440\u0443\u0433 \u043d\u0430 \u0434\u0440\u0443\u0433\u0430:<\/p>\n<pre><code class=\"kotlin\">object FlightTable : IntIdTable(\"flights\") {     val airplane = reference(\"airplane_id\", AirplaneTable, onDelete = ReferenceOption.CASCADE)     val toAirport = reference(\"to_airport_id\", AirportTable, onDelete = ReferenceOption.CASCADE) }  object AirportTable : IntIdTable(\"airports\") {     val iataCode = varchar(\"iata_code\", 32)     val country = varchar(\"country\", 128)     val city = varchar(\"city\", 128) }  object AirplaneTable : IntIdTable(\"airplanes\") {     val firm = varchar(\"firm\", 128)     val yearReleased = integer(\"year_released\")     val model = varchar(\"model\", 128) }<\/code><\/pre>\n<p>\u0410 \u0442\u0430\u043a\u0436\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438. \u0415\u0441\u043b\u0438 \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435\u043c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e <a href=\"https:\/\/github.com\/JetBrains\/Exposed\/wiki\/DAO#referencing\" rel=\"noopener noreferrer nofollow\">\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f<\/a><\/p>\n<pre><code class=\"kotlin\">class FlightEntity(id: EntityID&lt;Int>) : IntEntity(id) {     companion object : IntEntityClass&lt;FlightEntity>(FlightTable)      val airplane by AirplaneEntity referencedOn FlightTable.airplane     val toAirport by AirportEntity referencedOn FlightTable.toAirport      fun toFlight(): Flight = Flight(         airplane = airplane.toAirplane(),         toAirport = toAirport.toAirport()     ) }  class AirplaneEntity(id: EntityID&lt;Int>): IntEntity(id) {     companion object : IntEntityClass&lt;AirplaneEntity>(AirplaneTable)      val yearReleased by AirplaneTable.yearReleased     val firm by AirplaneTable.firm     val model by AirplaneTable.model      fun toAirplane() = Airplane(yearReleased, firm, model) }  class AirportEntity(id: EntityID&lt;Int>) : IntEntity(id) {     companion object : IntEntityClass&lt;AirportEntity>(AirportTable)      val country by AirportTable.country     val city by AirportTable.city     val iataCode by AirportTable.iataCode      fun toAirport() = Airport(country, city, iataCode) }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438: ER-\u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0441\u0445\u0435\u043c\u044b \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<figure class=\"full-width\">\n<div><figcaption>ER-\u0434\u0438\u0430\u0433\u0440\u0430\u043c\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u043f\u043e\u043b\u043d\u0438\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438:<\/p>\n<pre><code class=\"kotlin\">\/* 1 *\/ val airportID1 = AirportTable.insertAndGetId {     it[iataCode] = \"LED\"     it[country] = \"Russia\"     it[city] = \"St.Petersburg\" } val planeID1 = AirplaneTable.insertAndGetId {     it[yearReleased] = 2015     it[firm] = \"Airbus\"     it[model] = \"A320\" } FlightTable.insert {     it[toAirport] = airportID1     it[airplane] = planeID1 }  \/* 2 *\/ val airportID2 = AirportTable.insertAndGetId {     it[iataCode] = \"VKO\"     it[country] = \"Russia\"     it[city] = \"Moscow\" } val planeID2 = AirplaneTable.insertAndGetId {     it[yearReleased] = 2008     it[firm] = \"Boeing\"     it[model] = \"747\" } FlightTable.insert {     it[toAirport] = airportID2     it[airplane] = planeID2 }  \/* 3 *\/ val airportID3 = AirportTable.insertAndGetId {     it[iataCode] = \"DME\"     it[country] = \"Russia\"     it[city] = \"Moscow\" } val planeID3 = AirplaneTable.insertAndGetId {     it[yearReleased] = 2008     it[firm] = \"Sukhoi\"     it[model] = \"Superjet 100\" } FlightTable.insert {     it[toAirport] = airportID3     it[airplane] = planeID3 }<\/code><\/pre>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0432\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c: <strong>\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u0439\u0442\u0438 \u0432\u0441\u0435 \u0440\u0435\u0439\u0441\u044b, \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0435\u0441\u044f \u0432 \u0441\u0442\u0440\u0430\u043d\u0443 \u0420\u043e\u0441\u0441\u0438\u044f \u043d\u0430 \u0441\u0430\u043c\u043e\u043b\u0451\u0442\u0430\u0445, \u0432\u044b\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0445 \u043d\u0435 \u043f\u043e\u0437\u0436\u0435 2011 \u0433\u043e\u0434\u0430.<\/strong><\/p>\n<pre><code class=\"kotlin\">interface FlightRepository {        fun getFlightsToCountryByAirplaneYoungerThan(       destinationCountry: String,        youngerThanYear: Int     ): List&lt;Flight> }<\/code><\/pre>\n<p>\u0418\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0434\u043b\u044f \u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a<br \/>\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c. \u0422\u0430\u043a \u0447\u0442\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c<\/p>\n<h2>\u041d\u0430\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/h2>\n<p>\u0418\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u044f\u0441\u043d\u043e, \u0447\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0434\u0432\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<ol>\n<li>\n<p>DSL \u2013 \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u0430\u044f SQL-\u043f\u043e\u0434\u043e\u0431\u043d\u0430\u044f \u043e\u0431\u0451\u0440\u0442\u043a\u0430<\/p>\n<\/li>\n<li>\n<p>DAO \u2013 ORM-\u043e\u0431\u0451\u0440\u0442\u043a\u0430<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 N+1 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0435\u043d\u043d\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u0443 \u0441 ORM, \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Exposed DAO<\/p>\n<p>\u0418\u0437 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043f\u043e\u0438\u0441\u043a\u0430 \u0443 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 <code>Entity<\/code> \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0442\u043e\u0434\u043e\u0432:<\/p>\n<ul>\n<li>\n<p><code>get<\/code> \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043f\u043e ID \u0438\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0442\u0430\u043a\u043e\u0432\u043e\u0439<\/p>\n<\/li>\n<li>\n<p><code>findById<\/code> \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043f\u043e ID \u0438\u043b\u0438 <code>null<\/code> \u043f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0442\u0430\u043a\u043e\u0432\u043e\u0439<\/p>\n<\/li>\n<li>\n<p><code>find<\/code> \u0434\u043b\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u0430, \u043d\u043e \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>SqlExpressionBuilder<\/code><\/p>\n<\/li>\n<li>\n<p><code>all<\/code> \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"kotlin\">class PlainDaoFlightRepository : FlightRepository {      override fun getFlightsToCountryByAirplaneYoungerThan(         destinationCountry: String,         youngerThanYear: Int     ): List&lt;Flight> =         loggedTransaction {             FlightEntity.find {                 \/* AirportTable.country.lowerCase() eq destinationCountry.lowercase()                  and (AirplaneTable.yearReleased less youngerThanYear) *\/                 Op.nullOp()             }              FlightEntity.all().filter { flightEntity ->                 val targetCityMatches = flightEntity.toAirport.country.equals(destinationCountry, ignoreCase = true)                 val isYoungerThanYear = flightEntity.airplane.yearReleased &lt;= youngerThanYear                  targetCityMatches &amp;&amp; isYoungerThanYear              }.map(FlightEntity::toFlight)         }      override fun toString(): String = \"\u041d\u0430\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0447\u0435\u0440\u0435\u0437 Exposed DAO\" }<\/code><\/pre>\n<p>\u041f\u0440\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>find<\/code> \u0441 \u0443\u0441\u043b\u043e\u0432\u0438\u0435\u043c, \u0441\u0441\u044b\u043b\u0430\u044e\u0449\u0438\u043c\u0441\u044f \u043d\u0430 \u0432\u043d\u0435\u0448\u043d\u044e\u044e \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u0432\u044b\u043b\u0435\u0442\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"kotlin\">org.jetbrains.exposed.exceptions.ExposedSQLException:  org.h2.jdbc.JdbcSQLSyntaxErrorException: \u0421\u0442\u043e\u043b\u0431\u0435\u0446 \"AIRPORTS.COUNTRY\" \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d <\/code><\/pre>\n<p>\u0412\u0441\u0451 \u0434\u0435\u043b\u043e\u00a0\u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u00a0\u043f\u043e\u00a0\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 <code>SqlExpressionBuilder<\/code> \u0435\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u00a0\u0441\u0442\u043e\u043b\u0431\u0446\u0430\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u043d\u0430\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>find<\/code><\/p>\n<p>\u041f\u043e\u043a\u0430 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>all<\/code> \u0438 \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a\u00a0\u0440\u0435\u0448\u0435\u043d\u0438\u044e \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043f\u043e\u0437\u0436\u0435<\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0432 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0435\u0439 \u0432\u0441\u0435\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043b\u0438\u0441\u0442\u0438\u043d\u0433 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432:<\/p>\n<pre><code class=\"sql\">SQL: SELECT FLIGHTS.ID, FLIGHTS.AIRPLANE_ID, FLIGHTS.TO_AIRPORT_ID FROM FLIGHTS SQL: SELECT AIRPORTS.ID, AIRPORTS.IATA_CODE, AIRPORTS.COUNTRY, AIRPORTS.CITY FROM AIRPORTS WHERE AIRPORTS.ID = 1 SQL: SELECT AIRPLANES.ID, AIRPLANES.FIRM, AIRPLANES.YEAR_RELEASED, AIRPLANES.MODEL FROM AIRPLANES WHERE AIRPLANES.ID = 1 SQL: SELECT AIRPORTS.ID, AIRPORTS.IATA_CODE, AIRPORTS.COUNTRY, AIRPORTS.CITY FROM AIRPORTS WHERE AIRPORTS.ID = 2 SQL: SELECT AIRPLANES.ID, AIRPLANES.FIRM, AIRPLANES.YEAR_RELEASED, AIRPLANES.MODEL FROM AIRPLANES WHERE AIRPLANES.ID = 2 SQL: SELECT AIRPORTS.ID, AIRPORTS.IATA_CODE, AIRPORTS.COUNTRY, AIRPORTS.CITY FROM AIRPORTS WHERE AIRPORTS.ID = 3 SQL: SELECT AIRPLANES.ID, AIRPLANES.FIRM, AIRPLANES.YEAR_RELEASED, AIRPLANES.MODEL FROM AIRPLANES WHERE AIRPLANES.ID = 3<\/code><\/pre>\n<p>\u0422\u0438\u043f\u0438\u0447\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 N+1, \u043a\u043e\u0433\u0434\u0430 N \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u043b\u0435\u043d\u0438\u0432\u043e \u043f\u043e \u043c\u0435\u0440\u0435 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a \u043d\u0438\u043c.<\/p>\n<p>\u041d\u043e, \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0431\u044b, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-369138","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/369138","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=369138"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/369138\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=369138"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=369138"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=369138"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}