How to model an enum of String based static Ids in Scala? - scala

let's say I have a reference data table roles filled with all roles that a user might be granted. The rows are quite stable, meaning that it's uncommon that someone adds a new role to the table. Additionally there's a users table and a join-table users_roles. In fact, the roles table is just required to grant a user some predefined roles by adding a record to users_roles.
The roles table is quite simple:
CREATE TABLE IF NOT EXISTS admin.roles (
id CHAR(16) PRIMARY KEY,
description VARCHAR(256) NOT NULL
);
The following example describes a role:
INSERT INTO admin.roles VALUES('CS_AGENT', 'A customer service agent');
Obviously, I need the possible id values somewhere in my code. This is a set of Strings, but I'd like to prevent magic Strings and make this more type safe.
As far as I understand, there are several options:
create a symbol for each role id
create a new type RoleId that extends String and declare vals
In order to define the set of role ids, these are my options:
use an Enumeration
use a sealed trait/sealed object and derive case objects from it
I'm using JOOQ for my persistence layer, and it would be nice if I could use the type safe RoleId in my queries without manually converting it to String and vice versa.
What would be the best solution for this ?

I am not quite sure I get all of your problem, but would not something like this be the solution?
/** Represents a RoleId from the roles table. */
sealed trait RoleId {
def name: String
def description: String
override final def toString: String = name
}
object RoleId {
case object CS_AGENT extends RoleId {
override val name = "CS_AGENT"
override val description = "A customer service agent"
}
// Define all other roles...
/** All roles */
val allRoles: Set[RoleId] = Set(
CS_AGENT,
// All other roles...
)
/** Returns an RoleId given its name, if the name is not found this will return a None. */
def fromString(name: String): Option[RoleId] = name.toUpperCase match {
case "CS_AGENT" => Some(CS_AGENT)
// All other cases..
case _ => None
}
}
This is completely typesafe and if you need to go to/from a String there are the toString and fromString methods.
The only (big) downside of this approach is a lot of boilerplate code which is easy to screw up - creating a new RoleId but not adding it to the Set, typo in the name or in the case, etc.
An alternative to fixing this is to make this file autogenerated by SBT from some kind of config (even reading the SQL table if reachable in the build environment), for that part this answer of mine to another question may help.

Related

Kotlin JPA entity ID

What is "the kotlin way" to define JPA entity ID?
#Entity
data class User (
#Id #GeneratedValue
var id: Long? = null,
...
)
Or is there any better one to avoid nullable id?
You can use a 0 value rather than a null value.
#Entity
data class User (
#Id #GeneratedValue
var id: Long = 0,
...
)
Autogeneration should still find the next sequence.
Kotlin compiles to Java, which has both, a primitive type long and a Class Long
As per the Java Persistence Specification in section 11.1.21 Id Annotation both can be used for the Id:
The field or property to which the Id annotation is applied should be one
of the following types: any
Java primitive type; any primitive wrapper type; java.lang.String; java.util.Date;
java.sql.Date; java.math.BigDecimal; java.math.BigInteger[109].
There is an advantage in using the Class over the primitive, as null has a more unambiguous meaning. But from the spec both are possible and you have to decide weather you favor Kotlins nullsafety over the the jpa style or the other way around.
Usually, data class is useful to ruturn more that one result from a method , but not for entities (just my opinion).
Sometimes it is not a good idea to set a default value for the id field.
After some time experimenting with Kotlin and entities (actually, with documents for MongoDb, but anyway it has id),
Looks like the better way is to use lateinit var. You can create the top class of entity hierarchy:
open class Identifiable {
lateinit var id: Long // or String or UUID
//explicitly define equals & hash code here
}
But be careful, for equals, hashcode and if you want to provide toString method in heirs, then it is a good idea to provide extra nullable field, something like:
open class Identifiable {
lateinit var id: Long // or String or UUID
val nullableId: Long?
get() {
return if(this::id.isInitialized) id else null
}
//explicitly define equals & hash code here with nullableId
}
class User {
override fun toString() = "User(id=${nullableId})"
}
In this case, you will avoid an exception when you will try to log your created but not saved in DB entity

Mixing Table-Per-Hierarchy and Table-Per-Type in Entity Framework Code First to Existing Database

tl;dr: I'm trying to map a code-first model to an existing database where a certain hierarchy of objects has a mixed inheritance scheme. Some concrete classes use TPH and some use TPT. I can't seem to get the mapping correct.
I have a hierarchy of objects which I'm trying to map to an existing database. Some of the concrete classes contain additional properties, so they have their own table; some of the concrete classes do not, so they live in the base table and rely on a discriminator column. To simplify things, I've created a POC. The database structure is like this:
CREATE TABLE Foos (
Id INT IDENTITY NOT NULL PRIMARY KEY,
FooType TINYINT NOT NULL
)
CREATE TABLE FooTpts (
Id INT NOT NULL PRIMARY KEY
FOREIGN KEY REFERENCES Foos(Id),
Value INT NOT NULL
)
And the equivalent POCOs would be:
public abstract class Foo
{
public int Id { get; set; }
}
public class FooTph : Foo {}
public class FooTpt : Foo
{
public int Value { get; set; }
}
Seems simple enough. So my first try was the following mapping (fluent or with attributes, the result is the same):
modelBuilder.Entity<Foo>()
.ToTable("Foos")
.Map<FooTph>(m => m.ToTable("Foos").Requires("FooType").HasValue(1))
.Map<FooTpt>(m => m.ToTable("FooTpts").Requires("FooType").HasValue(2));
But that didn't work because:
It wants to create the FooTpt.FooType descriminator in the FooTpts table
Trying to execute a command gives me the following error (presumably because of point #1 above):
(6,10) : error 3032: Problem in mapping fragments starting at lines 6, 11:EntityTypes ConsoleApplication1.FooTph, ConsoleApplication1.FooTpt are being mapped to the same rows in table Foo. Mapping conditions can be used to distinguish the rows that these types are mapped to.
Back to the drawing board. This answer suggests creating an intermediate abstract entity mapped to the parent (TPH) table. Everything can always be solved with another layer of abstraction, right? So I make a few changes:
+ public abstract class FooTptBase : Foo {}
- public class FooTpt : Foo
+ public class FooTpt : FooTptBase
And change the mapping:
modelBuilder.Entity<Foo>()
.ToTable("Foos")
.Map<FooTph>(m => m.ToTable("Foos").Requires("FooType").HasValue(1))
.Map<FooTptBase>(m => m.ToTable("Foos").Requires("FooType").HasValue(2));
modelBuilder.Entity<FooTpt>().ToTable("FooTpts");
The database now looks good and we have a single discriminator in the parent table. But something is still missing and we get the same error:
(6,10) : error 3032: Problem in mapping fragments starting at lines 6, 11:EntityTypes ConsoleApplication1.FooTph, ConsoleApplication1.FooTpt are being mapped to the same rows in table Foo. Mapping conditions can be used to distinguish the rows that these types are mapped to.
That doesn't really make sense because all FooTpts have to be a FooTptBase by definition, which should require FooType == 2. (It's almost as if the model builder is ignoring my intermediate FooTptBase abstract type?)
So, what am I missing? How can I accomplish what I'm trying to do?

Play Framework 2.3 How to add unique constraint to sample application

Given the Play Framework 2.3 Computer Database sample application, I would like to practice adding a unique constraint on an attribute. Let's say I want the name attribute of the Computer class to be unique. I've tried to do this by adding a validate() function (and a getter) to Computer.java:
public List<ValidationError> validate() {
List<ValidationError> errors = new ArrayList<ValidationError>();
if(Computer.find.where().eq("name", getName()).findRowCount() != 0){
errors.add(new ValidationError("name", "Name must be unique. That value is already taken."));
}
return errors;
}
public String getName() {
return name;
}
This check works when creating new records in the database, however, this now causes a validation error when you update a Computer object but don't change the name. Is there a way to add a uniqueness constraint, similar to Rails? How can I validate uniqueness in Play?
Thanks!
UPDATE: see the answer by davide.
I ended up using the #Column(unique = true) constraint from the javax.persistence API. This doesn't generate an error in Play forms; instead, it throws a PersistenceException. Therefore I had to add change my controller to achieve the behavior I wanted. Both the create() and update() actions need a try/catch like this:
try {
computerForm.get().save();
} catch (PersistenceException pe) {
flash("error", "Please correct errors below.");
formData.reject("name", "Name conflict. Please choose a different name.");
return badRequest(createForm.render(computerForm));
}
UPDATE 2: each of the answers below is a possible solution
You need to exclude current entity from unique checking, i.e. like that:
if(Computer.find.where().eq("name", getName()).ne("id", getId()).findRowCount() != 0){
errors.add(new ValidationError("name", "Name must be unique."));
}
It will give you SQL query during update:
select count(*) from computer t0 where t0.name = 'Foo' and t0.id <> 123
And this during create:
select count(*) from computer t0 where t0.name = 'Foo' and t0.id is not null
P.S. ne() expression stands for Not Equal To and of course this approach assumes that your name field is Required
Edit: I sent you pull request with working solution, all you need is to add hidden field in your editForm like:
<input name="id" type="hidden" value='#computerForm("id").value'/>
Other thing is that you can simplify your model, i.e. don't need for getters for public fields.
I not sure if this answer your question, because I'm not familiar with Ruby syntax.
To "create a uniqueness constraint in the database" you can use the javax persistence API. Ebean will also recognize this.
To have a plain uniqueness constraint which involves a single field, you can use the #Column annotation:
#Entity
public class Computer extends Model {
...
#Column(unique = true)
public String name;
...
}
If you need some combination of fields to be unique, instead use the
#Table annotation
#Table(
uniqueConstraints=
#UniqueConstraint(columnNames={"name", "brand"})
)
#Entity
public class Computer extends Model {
...
public String name;
public String brand;
...
}
I hope it helps!

Lift-mapper - inserting items to database

I am trying to add item to H2 database. My code is:
class Test extends LongKeyedMapper[Test] with IdPK {
def getSingleton = Test
object name extends MappedString(this, 100)
}
and Test.create.name("some_name").id(2).save, but I always get java.lang.Exception: Do not have permissions to set this field. What can I do wrong? Connection is of course open and I have permission to data from database.
IdPK extends MappedLongIndex which is not writable by default, that's why it restricts you from setting the field. Usually you would let the DB generate an PK ID automatically for you via autoincrement field (postgres, mysql), trigger + sequence (oracle), etc. So in most common scenarios you don't need to set this field. To be able to still set it add an override like this on your field:
override def writePermission_? = true

Mapping custom types in the ScalaQuery O/R framework

In his comparison of ScalaQuery and Squeryl, Stefan Zeiger (author of ScalaQuery) says in the third bullet-point:
ScalaQuery comes with support for a basic set of JDBC types and can be
extended with DBMS- or application-specific types.
I have been unable to find examples or explanations for how to actually do this, however. I am trying to write a ScalaQuery schema for a Postgres database, in which some columns are of custom enum types that I created within Postgres.
For example, I have a enum type called gender, with possible values male and female. This is NOT a Java enum, persisted to the database as an integer. Rather, it is a custom Postgres type defined within the DBMS. Postgres stores those with a special 4-byte data structure rather than as a primitive.
How could I incorporate Postgres columns of type gender into a ScalaQuery schema?
(I would also appreciate comments, if you think a different strongly-typed O/R approach would be better suited for the task. I have already looked at Squeryl, and do not believe it can handle custom types unless they are persisted as primitives in the DBMS.)
import org.scalaquery.ql.{MappedTypeMapper => Mapper}
object TypeMapper {
type Stamp = java.sql.Timestamp
val joda2Stamp =
Mapper.base[JodaTime, Stamp](
dt => new Stamp(dt.getMillis),
ts => new JodaTime(ts.getTime) )
}
and then, for example, in your DAO (or wherever you run queries), use it:
import TypeMapper._
implicit val j2Stamp = joda2Stamp // type conversion automatically
You'll need to experiment to achieve the same for Enums and PostGres' enum storage type. I tend not to bother, preferring to go with Java Enums and storing as primitive type.
For example:
public enum CardType implements ILabel {
V("Visa"),
M("MasterCard"),
D("Discover"),
A("American Express");
private CardType(String label) { this.label = label; }
public String getLabel() { return this.label; }
final String label;
public static List<String> asList() {
return EnumHelper.asList(CardType.class);
}
public static Map<String,String> asMap() {
return EnumHelper.asMap(CardType.class);
}
}
and then store as char(1) in DB a la Orders.insert(cardType = cardType.toString), or you could create a type mapper Enum-String conversion and omit the enum.toString on inserts...