I'm doing a small CRUD application with Sqlite. My current solution is to pass a SqlConn to a manager class (like PersonManager) and one Database class with once methods for each manager to initialize them.
Code is like this:
class PersonManager
{
SqlConn dbSession
new make(SqlConn dbSession) { this.dbSession = dbSession }
Int insert(Person p)
{
dbSession.sql ...
}
}
class Database
{
SqlConn dbSession
new make(Uri uri) // opens database
once PersonManager()
{
PersonManager(dbSession)
}
}
In the Main pass database uri as a parameter
db := Database(`test.db`)
db.person.insert(Person { ... })
it works, but I've been looking at Service and I've found this topic http://fantom.org/forum/topic/1337, about services and databases, but I can't figure out how to do it, since SqlConn is not a const type and Service is const.
The thing is that I don't know how to share the database connection between the components. What are the database best practices?
Thanks
SlimerDudeWed 9 Nov 2016
Hi Fraya!
I'm going to paraphrase your question as "How do I safely make Database a const class so I can store it in a Service?"
Well, when you introduce the concurrent pod then const really means Thread Safe... so if your app runs in the one thread, like what an fwt gui application typically would, then it is fine to wrap the SqlConn in an Unsafe:
const class Database {
private const Unsafe dbSessionRef
SqlConn dbSession {
get { dbSessionRef.val }
set { throw ReadOnlyErr() }
}
new make(Uri uri) {
this.dbSessionRef = Unsafe(...)
}
PersonManager personManager() {
// as person manager doesn't / shouldn't hold state
// it's fine & lightweight to new up on every call
PersonManager(dbSession)
}
}
However, if your app is multi-threaded, such as a web application is, then Database should only store the URL and each threaded call to personManager() should create a new SqlConn:
using concurrent::Actor
const class Database {
const Uri dbUrl
new make(Uri uri) { ... }
PersonManager personManager() {
return Actor.locals.getOrAdd("myPersonManager") |->PersonManager| {
dbSession := ...
return PersonManager(dbSession)
}
}
}
Note how in both cases, the Database class above is const.
fraya Wed 9 Nov 2016
I'm doing a small CRUD application with Sqlite. My current solution is to pass a
SqlConn
to a manager class (likePersonManager
) and oneDatabase
class withonce
methods for each manager to initialize them.Code is like this:
it works, but I've been looking at
Service
and I've found this topic http://fantom.org/forum/topic/1337, about services and databases, but I can't figure out how to do it, since SqlConn is not a const type andService
is const.The thing is that I don't know how to share the database connection between the components. What are the database best practices?
Thanks
SlimerDude Wed 9 Nov 2016
Hi Fraya!
I'm going to paraphrase your question as "How do I safely make
Database
aconst
class so I can store it in aService
?"Well, when you introduce the
concurrent
pod thenconst
really means Thread Safe... so if your app runs in the one thread, like what an fwt gui application typically would, then it is fine to wrap theSqlConn
in anUnsafe
:However, if your app is multi-threaded, such as a web application is, then
Database
should only store the URL and each threaded call topersonManager()
should create a newSqlConn
:Note how in both cases, the
Database
class above isconst
.fraya Wed 9 Nov 2016
I've implemented the second and it's OK!
Thank you!!