Can't access delete method on Slick query - slick

This is very very very frustrating. I have been trying to pick up Slick for a while, and obstacles just keep coming. The concept of Slick is really awesome, but it is very difficult to learn, and unlike Scala, it doesn't have "beginner", "intermediate", and "advanced" style where people in all stages can use it easily.
I'm using Play-Slick (Slick 2.0.0) https://github.com/freekh/play-slick, following its Multi-DB cake example: https://github.com/freekh/play-slick/tree/master/samples/play-slick-cake-sample/app
For some reason, first, ddl does not belong to TableQuery, unlike the claim in the document: "The TableQuery‘s ddl method creates DDL". This shows through the scaladoc: http://slick.typesafe.com/doc/2.0.0/api/#scala.slick.lifted.TableQuery There is no ddl method there.
Second, my slick.lifted.Query can't generate delete method. It works fine with list, but not with delete.
val S3Files = TableQuery[S3Files]
S3Files.where(_.url === url).delete
This wouldn't work...then I tried:
val query = (for(s <- S3Files if s.url === url) yield s)
query.list //this works
query.delete //ehh?? can't find the method
val query2 = (for(s <- S3Files if s.url === url))
query2.delete //still won't work
Well...since Slick uses a very complicated (at least to newbies) implicit type conversion system, I don't really know what went wrong.

I tried it by simply adding
Cats.ddl.create
Cats.filter(_.name===cat.name).delete
to play-slick-cake-sample/app/controllers/Application.scala. Works fine for me.
Looks like you are using the wrong imports. Look at https://github.com/freekh/play-slick/blob/master/samples/play-slick-sample/app/controllers/Application.scala and mimic the imports.

slick 0.8.1 and slick 2.1.0 and I had the same Issue.
The reason why delete is not available on the Query is cause the play-slick Query does not contain a equivalent method of the delete method from slick Query.
I solved this Problem by changing to the original slick Driver
//import play.api.db.slick.Config.driver.simple._ //play-slick extensional Driver
import slick.driver.PostgresDriver.simple._ //original slick Driver

Related

Spark DataFrame Filter using Binary (Array[Bytes]) data

I have a DataFrame from a JDBC table hitting MySql and I need to filter it using a UUID. The data is stored in MySql using binary(16) and when querying out in spark is converted to Array[Byte] as expected.
I'm new to spark and have been trying various ways to pass a variable of type UUID into the DataFrame's filter method.
Ive tried statements like
val id: UUID = // other logic that looks this up
df.filter(s"id = $id")
df.filter("id = " convertToByteArray(id))
df.filter("id = " convertToHexString(id))
All of these error with different messages.
I just need to somehow pass in Binary types but can't seem to put my finger on how to do so properly.
Any help is greatly appreciated.
After reviewing even more sources online, I found a way to accomplish this without using the filter method.
When I'm reading from my sparkSession, I just use an adhoc table instead of table name, as follows:
sparkSession.read.jdbc(connectionString, s"(SELECT id, {other col omitted) FROM MyTable WHERE id = 0x$id) AS MyTable", props)
This pre-filters the results for me and then I just work with the data frame as I need.
If anyone knows of a solution using filter, I'd still love to know it as that would be useful in some cases.

Servicestack OrmLite "where exists" subquery

No matter how hard I tried I couldn't make it work and I'm not sure if it is possible.
I want to select all clients who have at least one order.
The first thing I tried was db.Exists as following:
SqlExpression<Client> exp = OrmLiteConfig.DialectProvider.SqlExpression<Client>();
exp.Where(x => Db.Exists<Order>(z => z.ClientId == x.Id));
but I get the following error
variable 'x' of type '[assembly].Client' referenced from scope '', but it is not defined`
Second try was using Join and SelectDistinct:
SqlExpression<Client> exp = OrmLiteConfig.DialectProvider.SqlExpression<Client>();
ev.Join<Client, Order>((b, a) => b.Id == a.ClientId)
.SelectDistinct(x => new { x.Id, x.ClientNumber, x.ClientNameName});
Although not optimal it worked, up to the moment when I needed paging for the result set through
ev.Limit(skip:((request.Page-1) * request.PageSize), rows:request.PageSize)
When using Limit the distinct logically get ignored in building the query, so I get now duplicate Clients.
Is there any other way, or in general is there away to handle subqueries in OrmLite?
Any help is appreciated.
ServiceStack OrmLite (currently at 4.0.x) does not have support for subqueries.
If you look at the 4.0.x docs , there is no discussion of subqueries. JOIN support has been added recently, but for advanced SQL, you need to write it yourself.
Honestly, at a certain point of complexity, SQL is more readable than advanced ORM/LINQ-style queries.

How to check if a table is already constructed?

Now I'm using Slick with Spray. I have to say Slick works much nicer alone, non-disturbingly with Spray than with Play (which is really troublesome).
However, I still can't solve a huge problem: database construction.
If there a way for me to maybe pass a list of TableQuery to a function, and it will match variables I passed in with tables in the database, and only create ones that are not created?
That would be really neat.
Assume I have two tables:
val articles = TableQuery[ArticleTable]
val users = TableQuery[UserTable]
I'm creating a function that may look like this:
def createDatabase(list: List[TableQuery[*]]) {
//.... (something like: (Article.articles.ddl ++ User.users.ddl).create)
}
Something like someTableQuery.baseTableRow.tableName should give you the table name. MTable.apply allows you to query for tables. Github search the slick code for examples of MTable.

subsonic query problem

I'm using subsonic 2.2 in an app. I'm running a little complicated query in I have used both "And" and "Or" for a field, I'm little confused about how it is going to be translated into sql statement
MytableCollection col = DB.Select().From("mytable").Where("prop1").IsEqualTo(obj.prop1)
.And("prop2").IsEqualTo(obj.prop2)
.And("prop3").IsEqualTo(obj.prop3)
.Or("prop1").IsEqualTo(1)
.ExecuteAsCollection<MytableCollection>();
I want to perform query like this.
select * from mytable where (prop1=obj.prop1 or prop1=1) and prop2=obj.prop2 and prop23=obj.prop3
As Andra says you can use AndExpression. This should do what you want:
MytableCollection col = DB.Select().From(Mytable.Schema)
.Where(Mytable.Columns.Prop2).IsEqualTo(obj.prop2)
.And(Mytable.Columns.Prop3).IsEqualTo(obj.prop3)
.AndExpression(Mytable.Columns.Prop1).IsEqualTo(obj.prop1)
.Or(Mytable.Columns.Prop1).IsEqualTo(1)
.ExecuteAsCollection<MytableCollection>();
N.B. using MyTable.Schema and MyTable.Columns will catch a lot of issues at compile time if you rename tablees and will save errors caused by mistyping
Something that is REALLY useful to know about is also the following two methods to call in your query building:
.OpenExpression()
and
.CloseExpression()
Mix those bad buoys and you have a lot better control over knowing where things start and finish
you can use expression in subsonic 2.2.
MytableCollection col = new Select(Mytable.Schema)
.WhereExpression("prop1").IsEqualTo(obj.prop1).Or("prop1").IsEqualTo(1)
.AndExpression("prop2").IsEqualTo(obj.prop2)
.AndExpression("prop3").IsEqualTo(obj.prop3)
.ExecuteAsCollection<MytableCollection>();

Subsonic : Same column name different tables

I have a query where I need to do a "Where" clause for two different columns in two different tables but subsonic creates the same parametrized parameter name for both which is causing an issue. How can I fix this?
string _RawSql = new Select()
.From(Tables.Table1)
.InnerJoin(Tables.Table2)
.InnerJoin(Table3.SidColumn, Table2.Table3SidColumn)
.Where(Table1.SidColumn).IsEqualTo(2)
.And(Table3.SidColumn).IsEqualTo(1)
.BuildSqlStatement();
The query this is creating is
SELECT ....
FROM [dbo].[Table1]
INNER JOIN [dbo].[Table2] ON [dbo].[Table1].[Table2Sid] = [dbo].[Table2].[Sid]
INNER JOIN [dbo].[Table3] ON [dbo].[Table2].[Table3Sid] = [dbo].[Table3].[Sid]
WHERE [dbo].[Table1].[Sid] = #Sid
AND [dbo].[Table3].[Sid] = #Sid
Note that in the last two lines its using #Sid for both Table1 and Table3. How go I do it so it uses #Sid0 and #Sid1?
Any help would be appreciated. Thanks
Thanks for the response, I really appreciate it. I am using 2.1
I am already using TableColumn. Below is the c# subsonic code...
.Where(Table1.SidColumn).IsEqualTo(2)
.And(Table3.SidColumn).IsEqualTo(1)
which creates the following sql when viewed in sql profiler
WHERE [dbo].[Table1].[Sid] = #Sid
AND [dbo].[Table3].[Sid] = #Sid
Could you please show me how can I replace these lines with the way you are suggesting? I would really rather not use literal "Table2.Sid = 2"
ranmore, the issue is same with variables or with constants.
I have even tried
.Where("Table1.Sid").IsEqualTo(2)
.And("Table3.Sid").IsEqualTo(1)
This creates the query as
WHERE Table1.Sid = #Table1.Sid0
AND Table3.Sid = #Table3.Sid1
I finally get different parametrized vars in this case but now SQL Server complains because it does not like . in the parametrized var names.
I have no clue how to perform a join with 2 where clauses for 2 different tables!
What version are you using? In 2.2 You can use the TableColumn object to get around this (it may be the same for 2.1 as well. So instead of using the struct, as you're doing, you can use the object (Table2.SidColumn).
If push comes to shove - you can override everything with a string - so in your case you could use "Table1.Sid" and "Table2.Sid" right in the Where() method.
I haven't been able to confirm this, but perhaps the problem only happens with literals? (not sure if your sample code is like that for brevity's sake)
int table1SidColumnValue = 2;
int table3SidColumnValue = 1;
.Where(Table1.SidColumn).IsEqualTo(table1SidColumnValue)
.And(Table3.SidColumn).IsEqualTo(table2SidColumnValue)
I remember seeing a problem with this when using multiple .In() clauses with literal values, not sure if that applies to your problem though.
I'm not sure what version of the code I have but your query produces numbered parameters for me.
If you look at Line 255 of ANSISqlGenerator.cs
https://github.com/subsonic/SubSonic-2.0/blob/master/SubSonic/SqlQuery/SqlGenerators/ANSISqlGenerator.cs
c.ParameterName = String.Concat(col.ParameterName, query.Constraints.IndexOf(c));
The where parameters really should have numbers appended to them... maybe pull the latest version?

Resources