Virtual attribute of ActiveJDBC model - activejdbc

I had a ActiveJDBC model called Job, and defined some static attributes like title, salary, workplace and so on.
public class Job extends Model {
public String getTitle() {
return getString("title");
}
public void setTitle(String title) {
setString("title", title);
}
public Integer getSalary() {
return getInteger("salary");
}
public void setSalary(Integer salary) {
setInteger("salary", salary);
}
public String getWorkplace() {
return getString("workplace");
}
public void setWorkplace(String workplace) {
setString("workplace", workplace);
}
}
Now I want to find jobs based on geometry distance by below sql:
String sql = "select *, ST_distance(...) as distance from jobs... order by distance asc";
LazyList<Job> jobs = Job.findBySql(sql);
How can I read the virtual attribute distance from Job model?
I have tried to add distance column in jobs table, and it reported error ERROR: ORDER BY "distance" is ambiguous

Not sure what you mean by a "virtual" attribute, but ActiveJDBC models are just Java classes, so you can add whatever you want to them. JavaLite will not be handling them for you though. It is your responsibility to add appropriate setters and getters and maintain their state as if this was a regular Java class.
So, you want this wrapped into a model:
String sql = "select *, ST_distance(...) as distance from jobs... order by distance asc";
LazyList<Job> jobs = Base.findAll(sql);
you are on the right path. Please, read the JavaDoc for this method carefully:
http://javalite.github.io/2.4-j8/org/javalite/activejdbc/Model.html#findBySQL-java.lang.String-java.lang.Object...-
Especially focus on this part: "Ensure that the query returns all columns associated with this model, so that the resulting models could hydrate themselves properly.".
The "*" in your query takes care of the first part, and the second part will be ignored by a model automatically but will participate in the selection: " Returned columns that are not part of this model will be ignored, but can be used for clauses like above."
So, all you have to do is to write a method like this:
public class Job{
public List<Map> getNearJobs(){
String sql = "select *, ST_distance(. ? . ? .) as distance from jobs... order by distance asc";
return Base.findAll(sql, getLogitude(), getLatitude());
}
}
this way, you will construct a query that will bring (and order) the right maps with their attributes filled appropriately.
So, you will get a list of Maps, not Jobs, but it will include all the data you need. You can use this approach with some code acrobatics to create new models from a list of maps (Model.fromMap()) and separately inject your "distance" attribute in each model. However, I'm personally against this because then a model is not a model since a model is mapping to a table.

Related

ActiveJDBC: use scope with dynamic parameters

The actual scope examples provide the use of hard-coded parameters passed to the query:
public class Employee extends Model {
static {
addScope("byDepartment", "department = 'marketing'");
}
}
Is it possible to make that parameter dynamic and all the scope as follows:
public class Employee extends Model {
static {
addScope("byDepartment", "department = '?'");
}
}
Example of use:
Employee.scope("byDepartment").where(....) <-- how to pass in a department value ?
Thank you.
Current implementation only works with hard-coded scopes. In general, having dynamic scopes is not any different than just having an additional parameter in a where() method, but will significantly complicate the implementation.
This question prompts for some philosophical discussion. Normally, you would be using a model as its own service. In other words, using a model like this from outside the model is not a preferred way:
List<Employee> employees = Employee.scope("byDepartment").where("start_date > ?", startDate);
It is best to wrap all access to the EMPLOYEES table into the Employee class like this:
public class Employee extends Model{
public static List<Employee> getStartedByDepartment(Date started, String department){
return Employee.scope(department).where("start_date > ?", started);
}
}
We code all JavaLite projects with this pattern, and do not allow ActiveJDBC API to bleed outside models (for the most part, lol).
As you can see, there is little that scopes will give you as the internal implementation of the model may or may not use scopes, you will get the same results. This coding pattern is much better becuase:
You have static methods on Models you can test
You have static methods that may have guard statements if (department = null) throw new IllegalArgumentException("blah...")
You have static methods on Models that have good semantic names
The implementation and access to your table is wrapped in one class, and not bled outside (controllers).
Easy to do refactoring down the road.
However, if you use this approach, the value of scopes is near zero.
Needless to say, I do not use scopes in my work.
I do not see anything wrong in making the parameter dynamic like in your Employee model:
public class Employee extends Model {
static {
addScope("byDepartment", "department = '?'");
}
}
the issue is actually with
Employee.scope("byDepartment").where(....)
beside the scopeName, scope() does not provide any way for extra params for the scopeValue(s).
Instead you can call Employee.where(subquery, params)
where subquery would be your scopeQuery that you can access with ModelDelegate.getScopes().get(scopeName) and params would be your scopeValue.

How to easily access widely different subsets of fields of related objects/DB tables?

Imagine we have a number of related objects (equivalently DB tables), for example:
public class Person {
private String name;
private Date birthday;
private int height;
private Job job;
private House house;
..
}
public class Job {
private String company;
private int salary;
..
}
public class House {
private Address address;
private int age;
private int numRooms;
..
}
public class Address {
private String town;
private String street;
..
}
How to best design a system for easily defining and accessing widely varying subsets of data on these objects/tables? Design patterns, pros and cons, are very welcome. I'm using Java, but this is a more general problem.
For example, I want to easily say:
I'd like some object with (Person.name, Person.height, Job.company, Address.street)
I'd like some object with (Job.company, House.numRooms, Address.town)
Etc.
Other assumptions:
We can assume that we're always getting a known structure of objects on the input, e.g. a Person with its Job, House, and Address.
The resulting object doesn't necessarily need to know the names of the fields it was constructed from, i.e. for subset defined as (Person.name, Person.height, Job.company, Address.street) it can be the array of Objects {"Joe Doe", 180, "ACompany Inc.", "Main Street"}.
The object/table hierarchy is complex, so there are hundreds of data fields.
There may be hundreds of subsets that need to be defined.
A minority of fields to obtain may be computed from actual fields, e.g. I may want to get a person's age, computed as (now().getYear() - Person.birtday.getYear()).
Here are some options I see:
A SQL view for each subset.
Minuses:
They will be almost the same for similar subsets. This is OK just for field names, but not great for the joins part, which could ideally be refactored out to a common place.
Less testable than a solution in code.
Using a DTO assembler, e.g. http://www.genericdtoassembler.org/
This could be used to flatten the complex structure of input objects into a single DTO.
Minuses:
I'm not sure how I'd then proceed to easily define subsets of fields on this DTO. Perhaps if I could somehow set the ones irrelevant to the current subset to null? Not sure how.
Not sure if I can do computed fields easily in this way.
A custom mapper I came up with.
Relevant code:
// The enum has a value for each field in the Person objects hierarchy
// that we may be interested in.
public enum DataField {
PERSON_NAME(new PersonNameExtractor()),
..
PERSON_AGE(new PersonAgeExtractor()),
..
COMPANY(new CompanyExtractor()),
..
}
// This is the container for field-value pairs from a given instance of
// the object hierarchy.
public class Vector {
private Map<DataField, Object> fields;
..
}
// Extractors know how to get the value for a given DataField
// from the object hierarchy. There's one extractor per each field.
public interface Extractor<T> {
public T extract(Person person);
}
public class PersonNameExtractor implements Extractor<String> {
public String extract(Person person) {
return person.getName();
}
}
public class PersonAgeExtractor implements Extractor<Integer> {
public int extract(Person person) {
return now().getYear() - person.getBirthday().getYear();
}
}
public class CompanyExtractor implements Extractor<String> {
public String extract(Person person) {
return person.getJob().getCompany();
}
}
// Building the Vector using all the fields from the DataField enum
// and the extractors.
public class FullVectorBuilder {
public Vector buildVector(Person person) {
Vector vector = new Vector();
for (DataField field : DataField.values()) {
vector.addField(field, field.getExtractor().extract(person));
}
return vector;
}
}
// Definition of a subset of fields on the Vector.
public interface Selector {
public List<DataField> getFields();
}
public class SampleSubsetSelector implements Selector {
private List<DataField> fields = ImmutableList.of(PERSON_NAME, COMPANY);
...
}
// Finally, a builder for the subset Vector, choosing only
// fields pointed to by the selector.
public class SubsetVectorBuilder {
public Vector buildSubsetVector(Vector fullVector, Selector selector) {
Vector subsetVector = new Vector();
for (DataField field : selector.getFields()) {
subsetVector.addField(field, fullVector.getValue(field));
}
return subsetVector;
}
}
Minuses:
Need to create a tiny Extractor class for each of hundreds of data fields.
This is a custom solution that I came up with, seems to work and I like it, but I feel this problem must have been encountered and solved before, likely in a better way.. Has it?
Edit
Each object knows how to turn itself into a Map of fields, keyed on an enum of all fields.
E.g.
public enum DataField {
PERSON_NAME,
..
PERSON_AGE,
..
COMPANY,
..
}
public class Person {
private String name;
private Date birthday;
private int height;
private Job job;
private House house;
..
public Map<DataField, Object> toMap() {
return ImmutableMap
.add(DataField.PERSON_NAME, name)
.add(DataField.BIRTHDAY, birthday)
.add(DataField.HEIGHT, height)
.add(DataField.AGE, now().getYear() - birthday.getYear())
.build();
}
}
Then, I could build a Vector combining all the Maps, and select subsets from it like in 3.
Minuses:
Enum name clashes, e.g. if Job has an Address and House has an Address, then I want to be able to specify a subset taking street name of both. But how do I then define the toMap() method in the Address class?
No obvious place to put code doing computed fields requiring data from more than one object, e.g. physical distance from Address of House to Address of Company.
Many thanks!
Over in-memory object mapping in the application, I would favor database processing of the data for better performance. Views, or more elaborate OLAP/datawarehouse tooling could do the trick. If the calculated fields remain basic, as in "age = now - birth", I see nothing wrong with having that logic in the DB.
On the code side, given the large number of DTOs you have to deal with, you could use classless dynamic (available in some JVM languages) or JSON objects. The idea is that when a data structure changes, you only need to modify the DB and the UI, saving you the cost of changing a whole bunch of classes in between.

Sql error when using GORM's dynamic FindAllBy method - #2 is not set

I have those domain classes:
class Person{
String username
}
class Course {
String code
static hasMany = [events:Event]
}
class Event {
Long id
String name
(...)
static belongsTo = [course:Course, parallel:Parallel]
static hasMany = [teachers: Person, students: Person,bought: Exchange, sold: Exchange]
}
And what I want to do is find all the events associated with a student and a course. I did this query:
(...)
println "User: ${person.username}"
println "Course: ${course.code}"
Set<Person> persons = []
persons.add(person)
def events = Event.findAllByCourseAndStudents(course, persons)
}
But that is giving me an error ERROR util.JDBCExceptionReporter - Parameter "#2" is not set; SQL statement:
What am I missing here?
The issue with the second parameter in your query Students is the fact it's an 1:M (one to many) association and querying these associations using dynamic finders is not supported.
Take a look at this quick overview of the various types of querying supported by GORM/Grails to get a better understanding of what kind of options are available to you and when to use them.
As you can see using a criteria is really what you need in this case:
def events = Event.createCriteria().list() {
eq('course', course)
students {
eqId(person.id)
}
}
}
The above only matches against a single person, but you can modify this further to use a list of persons as you intend. I will leave that exercise to you so you can become familiar with how to create and use criteria.

How do I make a well designed validation for a complex collection model?

As input I have a list of Books. As output I expect a SimilarBookCollection.
A SimilarBookCollection has an author, publishYear and list of Books. The SimilarBookCollection can't be created if the author of the books is different or if the publishYear is different.
The solution so far in PHP:
client.php
----
$arrBook = array(...); // array of books
$objValidator = new SimilarBookCollectionValidator($arrBook);
if ($objValidator->IsValid()) {
$objSimilarBookCollection = new SimilarBookCollection($arrBook);
echo $objSimilarBookCollection->GetAuthor();
}
else {
echo 'Invalid input';
}
SimilarBookCollection.php
---
class SimilarBookCollection() {
public function SimilarBookCollection(array $arrBook) {
$objValidator = new SimilarBookCollectionValidator($arrBook);
if ($objValidator->IsValid()) {
throw new Exception('Invalid books to create collection');
}
$this->author = $arrBook[0]->GetAuthor();
$this->publishYear = $arrBook[0]->GetPublishYear();
$this->books = $arrBook;
}
public function GetAuthor() {
return $this->author;
}
public function GetPublishYear() {
return $this->publishYear;
}
public function GetBooks() {
return $this->books;
}
}
SimilarBookCollectionValidator.php
---
class SimilarBookCollectionValidator() {
public function IsValid() {
$this->ValidateAtLeastOneBook();
$this->ValidateSameAuthor();
$this->ValidateSameYear();
return $this->blnValid;
}
... //actual validation routines
}
The goal is to have a "special" collection with only books that have the same author and publishYear. The idea is to easily access the repeating information like author or year from the object.
How would you name the SimilarBookCollection? The current name is to
generic. Using a name like SameYearAuthorBookCollection looks a bit
long and strange(if more conditions will be added then name will increase)
Would you use a Validator in SimilarBookCollection constructor using a
defensive programming style?
Would you change the design of the code? If yes how?
It all depends ;)
So if I were to aim for a generic adaptable solution I would do the following:
Validator in constructor
On one hand you are validating twice; that is informative in case of a broken precondition/contract (not giving a valid list), but is double the code to run - for what purpose exactly?
If you want to use this in a system depends on its size, how critical it is, product phase, and likely more criterias.
But then it also is controller logic fitted into a model meaning you are spreading your code around.
I would not put it in the constructor.
Name / Design
I would say keep the BookCollection generic as it is, and have any validation strictly in the controller space, instead of bloating the collection which essentially seems to be an array with the extra field of author.
If you want to differentiate between different collection types use either (multiple) inheritance or some sort of additional field "collectionType"; the former if you expect many derivatives or varying functionality to come (also keeps the logic where different nicely separated).
You could also consider your collection as a set on which you perform queries and for convenience's sake you could maintain some sort of meta data like $AuthorCount = N, $publicationDates = array(...) from which you can quickly derive the collection's nature. This approach would also keep your validator-code minimal (or non-existent), as it'd be implicitly in the collection and you could just do the validation in the controller keeping the effective logic behind it clearly visible.
That would also make it more comfortable for you in the future. But the question really is what you want and need it for, and what changes you expect, because you are supposed to fit your design to your requirements and likely changes.
For your very particular problem the constraints as I understand are as follows:
There is only one collection type class in the system at any given
point in time.
The class's items have several attributes, and for a particular, possibly changing subset of these (called identical attributes), the collection only accepts item lists where the chosen attributes of all items are identical.
The class provides getters for all identical attributes
The class must not be usable in any other way than the intended way.
If not for point 1 I would use a generic base class that is either parametrized (ie you tell it upon instantiation which is the set of identical attributes) or uses multiple inheritance (or in php traits) to compose arbitrary combinations with the needed interfaces. Children might rely on the base class but use a predefined subset of the identical attributes.
The parametrized variant might look something as follows:
class BookCollection {
public function __construct($book_list, $identical_fields=array())
{
if (empty($book_list))
{
throw new EmptyCollectionException("Empty book list");
}
$default = $book_list[0];
$this->ia = array();
foreach($identical_fields as $f)
{
$this->ia[$f] = $default->$f;
}
foreach($book_list as $book)
{
foreach($identical_fields as $f)
{
if ($this->ia[$f] !== $book->$f)
{
throw new NotIdenticalFieldException("Field $f is not identical for all");
}
}
}
$this->book_list = $book_list;
}
public function getIdentical($key)
{
$this->ia[$key];
}
}
final class BC_by_Author extends BookCollection{
public function __construct($book_list)
{
parent::__construct($book_list,array('author'));
}
public function getAuthor(){ $this->ia['author']; }
}
or fooling around with abstract and final types (not sure if it's valid like this)
abstract class BookCollection{
public final function __construct($book_list){...}
abstract public function getIdenticalAttributes();
}
final class BC_by_Author {
public function getIdenticalAttributes(){ return array('author'); }
public function getAuthor(){ return $this->ia['author']; }
}
If you rely on getters that do not necessarily match the field names I would go for multiple inheritance/traits.
The naming then would be something like BC_Field1Field2Field3.
Alternatively or additionally, you could also use exactly the same classname but develop your solutions in different namespaces, which would mean you wouldn't have to change your code when you change the namespace, plus you can keep it short in the controllers.
But because there will only ever be one class, I would name it BookCollection and not unnecessarily discuss it any further.
Because of constraint 4, the white box constraint, the given book list must be validated by the class itself, ie in the constructor.

Returning datasets from LINQ to SQL in a REST/WCF service

I have a WCF/REST web service that I'm considering using Linq to SQL to return database info from.
It's easy enough to do basic queries against tables and return rows, for example:
[WebGet(UriTemplate = "")]
public List<User> GetUsers()
{
List<User> ret = new List<User>(); ;
using (MyDataContext context = new MyDataContext())
{
var userResults = from u in context.Users select u;
ret = userResults.ToList<User>();
}
return ret;
}
But what if I want to return data from multiple tables or that doesn't exactly match the schema of the table? I can't figure out how to return the results from this query, for example:
var userResults = from u in context.Users
select new { u.userID, u.userName, u.userType,
u.Person.personFirstname, u.Person.personLastname };
Obviously the resulting rowset doesn't adhere to the "User" schema, so I can't just convert to a list of User objects.
I tried making a new entity in my object model that related to the result set, but it doesn't want to do the conversion.
What am I missing?
Edit: related question: what about results returned from stored procedures? Same issue, what's the best way to package them up for returning via the service?
Generally speaking, you shouldn't return domain objects from a service because if you do you'll run into issues like those you're finding. Domain objects are intended to describe a particular entity in the problem domain, and will often not fit nicely with providing a particular set of data to return from a service call.
You're best off decoupling your domain entities from the service by creating data transfer objects to represent them which contain only the information you need to transfer. The DTOs would have constructors which take domain object(s) and copy whatever property values are needed (you'll also need a parameterless constructor so they can be serialized), or you can use an object-object mapper like AutoMapper. They'll also have service-specific features like IExtensibleDataObject and DataMemberAttributes which aren't appropriate for domain objects. This frees your domain objects to vary independently of objects you send from the service.
You can create a Complex Type and instead of returning Anonymous object you return the Complex Type. When you map stored procedures using function import, you have a option to automatically create a complex type.
Create a custom class with the properties that you need:
public class MyTimesheet
{
public int Id { get; set; }
public string Data { get; set; }
}
Then create it from your Linq query:
using (linkDataContext link = new linkDataContext())
{
var data = (from t in link.TimesheetDetails
select new MyTimesheet
{
Id = t.Id,
Data = t.EmployeeId.ToString()
}).ToList();
}