I have an application which is using Play Framework 2.1.x with Ebean. I would like to use SQL views (PostgreSQL v9.3) instead of actual tables. I tried to switch the "name" property in #Table annotation from actual table name to view name. Retrieving data from view to Ebean model works nice, but when there is a ManyToMany association, it generates an error. The problem is in name convention used by Ebean in order to generate JOIN clauses in SQL query.
For example I have a table named "customers" and a view named "customers_view" and ManyToMany association with table "customertags". In such case, Ebean generates JOIN clause using bridge table "customers_customerstags". But when I change #Table`s name property to "customers_view", associations are messed up. Ebean then generates JOIN with table "customers_view_customerstags" and so on.
I know that this can be fixed by using #JoinTable and #JoinColumn, BUT at first I want to ask some more experienced programmers if there is some other proper way on how to use SQL views in Play/Ebean which I am missing ?
I don't think you are missing anything. In the absence of #JoinTable etc Ebean is using a naming convention based on the table name (which is now your view).
An alternative work around to this issue by creating a view for the intersection table.
I also found a partial solution for this. There is a function in Ebean`s ServerConfig class called setNamingConvention. With this function you can set your own implementation of interface NamingConvention or you can override functions in included classes from Ebean.
I tried to override Ebean`s default implementation called UnderscoreNamingConvention. By overriding of function getM2MJoinTableName I was able to fix errors regarding creation of join table name in SQL query. Unfortunately join columns are still wrong. Join columns are generated from function NamingConvention.getTableName. It is also possible to override this function, but such change would break generation of FROM part of SQL.
Too bad there is no way to override generation of join columns in NamingConvention interface.
It seems there is no escape from this. Reasonable workaround is to use #JoinTable.
Related
How could I apply View to enforce backwards compatibility with old queries that rely on old schema if the following change happens:
T(A1(key), A2)
to
T(A1(key), A2(key))
Basically we would make second attribute to be a joined key with first attribute.
Is there any standard way of doing it across diff sql languages?
If not I am interested in SQLite/SQLite3.
Thanks you!
I would have thought that you'd treat this no different to a table, other than not having to worry about the actual data.
That is include it in the older schema to work with the older schema and then upgrade it to the new schema along with the tables by using
DROP VIEW IF EXISTS your_view;
CREATE VIEW IF NOT EXISTS your_view .............;
For other SQL, again as for tables, you may find it simpler to just use the often more extensive ALTER commands.
Without specifics it's hard to say whether or not a single standard method could be adopted.
Is there a method to automatically join tables that have primary to foreign relationship rather then designate joining on those values?
The out and out answer is "no" - no RDBMS I know of will allow you to get away with not specifying columns in an ON clause intended to join two tables in a non-cartesian fashion, but it might not matter...
...because typically multi tier applications these days are built with data access libraries that DO take into account the relationships defined in a database. Picking on something like entity framework, if your database exists already, then you can scaffold a context in EF from it, and it will make a set of objects that obey the relationships in the frontend code side of things
Technically, you'll never write an ON clause yourself, because if you say something to EF like:
context.Customers.Find(c => c.id = 1) //this finds a customer
.Orders //this gets all the customer's orders
.Where(o => o.date> DateTIme.UtcNow.AddMonths(-1)); //this filters the orders
You've got all the orders raised by customer id 1 in the last month, without writing a single ON clause yourself... EF has, behind the scenes, written it but in the spirit of your question where there are tables related by relation, we've used a framework that uses that relation to relate the data for the purposes thtat the frontend put it to.. All you have to do is use the data access library that does this, if you have an aversion to writing ON clauses yourself :)
It's a virtual certaintythat there will be some similar ORM/mapping/data access library for your front end language of choice - I just picked on EF in C# because it's what I know. If you're after scouting out what's out there, google for {language of choice} ORM (if you're using an OO language) - you mentioned python,. seems SQLAlchemy is a popular one (but note, SO answers are not for recommending particular softwares)
If you mean can you write a JOIN at query time that doesn't need an ON clause, then no.
There is no way to do this in SQL Server.
I am not sure if you are aware of dbForge; it may help. It recognises joinable tables automatically in following cases:
The database contains information that specifies that the tables are related.
If two columns, one in each table, have the same name and data type.
Forge Studio detects that a search condition (e.g. the WHERE clause) is actually a join condition.
I was wondering if it is a good (acceptable) practice to combine those to ways of retrieving/updating database data?
For example, in my database I have two tables (Books and Users) and one "many-to-many" table Books_Users. When a user rates a book, the Books_Users table should be updated (a new record with a book_id and a user_id should be whether inserted or deleted).
I googled ways of doing it using AR methods only, but I haven't found any good solution. I ended up using CDbCommand execute() and very simple SQL-query like INSERT INTO books_users(book_id, user_id) VALUES(:bid , :uid); in a BookController action.
The point is that all my models extend CActiveRecord, and I use AR methods all the way.
So here is the question: is that kind of blending of different approaches could be used without remorse, or I should get rid of it immediately and write the code in some "proper way"?
Yii does support Many_TO_Many relations (to some degree) and this support has been improving through the 1.1.x releases http://www.yiiframework.com/doc/guide/database.arr.
Generally i don't think you will have to use CDbCommand & get dirty with SQL, you shouldn't face any problems doing it with AR specially the retrieval part, However, Insertion (Create/Update) Could be a problem (not a huge one though) since it can be solved with some triggers either on database level (database triggers) or App level (Model afterCreate() & afterUpdate()) to automate populating/updating the middle table (pivot) records.
Another (cleaner) way would be to use this extension: http://www.yiiframework.com/extension/cadvancedarbehavior/ which should do the job for you.
Last thing: take a look at this question and this one for related inquires.
I am trying to find a way to only populate a property of my entity class, if the column exists in the query?
When I execute a query using DbSet.SqlQuery and returning the column (which is an alias) populated, everything is fine. But when using the built in functionality such as All(), Find(), ToArray() etc, it expects that column to be in the dataset.
Is there a way (without having to write all of the supporting queries manually) to mark a property in my entity class, as optional.
It is currently marked as a nullable DateTime but the framework still complains it does not exist when using the built in functionality.
Any suggestions would be great!
Cheers
No, because they have to build the SQL query. It doesn't matter if a column is nullable or not, what matters is that when they build the query, if that column does not exist, then the database will likely throw an error complaining that the column does not exist.
The only way around it is to not map it, or to query the schema when mapping and conditionally map the property (though I wouldn't recommend that).
I have a named hql query which makes use of object constructors for an object that is not mapped (it is only imported)
e.g.
select distinct new NotMappedResultClass(ah.SomeProp1, ah.SomeProp2)
from SomeMappedClass
where ...
order by ah.SomeProp1
The weird thing is, that when I call IQuery.List() in NHibernate, I end up with exactly twice as many rows from NHibernate than from the query that NHibernate ran (traced using SqlProfiler).
(In case it matters, the "where" clause does actually involve some subqueries).
Why is NHibernate duplicating the rows coming back from the database?
(I am using NHibernate 1.2.1.4000)
Found the problem.
My project has some odd mappings when it comes to inherited classes.
Basically, SomeMappedClass was abstract, and had its own NHibernate mapping, and there was a derived class SomeDerivedClass (that didn't add any functionality) that was also mapped separately without the "extends" attribute.
This caused NHibernate to issue two sql queries, with different aliases for the same table.
In my case the simple quick and dirty solution was to query from SomeDerivedClass instead of SomeMappedClass, but the more appropriate solution would probably be to modify the mappings / object inheritance.