Yii: combination of CDbCommand and ActiveRecord queries in one Controller/Action - sql

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.

Related

How to avoid defining two extra tables for an object that can have only 3 possible values and is part of a many-to-many relationship?

I tried to search this online but found this question quite difficult to formulate in a concise & intelligible way.
I am developing an application which enables users to choose from 3 types of authentications: Password, Finger Print & Face Recognition. Each user may opt for multiple types of these 3 and I need to store their picks in a relational database. So theoretically, there exists a many-to-many relationship between users and authentication_types.
I know this seems quite trivial and probably I am overanalysing things, but which would be the optimal way to model this at a relational database level? What I am trying to avoid but seems to be the only reasonable solution in a relational DB setting, is to create a table for login types (say LoginTypes) in which to store the 3 login types mentioned above and create an intermediary table for the many-to-many relationship (say UsersLoginTypes).
What's frustrating a little for me is that for only 3 types of login, I need to create one table to store them and another one for the many-to-many relationship. And any time I want to get the login types chosen by a user, I cannot simply select the user and extract the login types from the user's object, but I need to make a query that involves two another tables (LoginTypes & UsersLoginTypes). Do I miss a simpler solution here?
I thought of maybe assigning each login type a digit (eg. Password - 1, Fingerprint - 2, Face Recognition - 3) and have a field in the User's model for the login types, where to store a string containing the digits corresponding to what the user chose. And eventually, this is perhaps what I would go for if no better solution exists.
PS. I am using Ruby on Rails with ActiveRecord, if this changes something.
In 1997, I once normalised a relational database model to death. It worked, was extremely flexible, but it invariably ground to a halt whenever you wanted to formulate an unforeseen query. It was already very tedious to formulate the query in the first place. (of course, that was at times when you always wrote your SQL manually - BI tools were a thing of the future).
So: a (master) table users , a (lookup) table login_types and a (child/intermediate) table active_users_authentications as your first shot is the correct way of modelling it relationally.
But if you want the system to be efficient/performant (and you don't need any further details for the authentication configurations - which you would store in active_users_authentications, of course), I for one would find it absolutely legitimate to have 3 Booleans (Yes/No) columns in the users table and call them: has_pwd_auth, has_fgnpr_auth, and has_facerec_auth .

Polymorphic Associations in SQL

I'm creating a project with big database of Movies and Series, both in seperate tables. Now I have other tables like Country for specifying production country of movie or/and serie. If I want to do this in many to many relation it requires connection table one for movie and one for serie. It would look like this:
DB with separate connection tables.
It is many tables, so I was searching for other solutions and I found this article and the "Using one data entity per class" method seems to be best for me. I implemented it like that: DB with combined connection table.
The second implementation seems to be good, but there's a one problem I'm facing and that's a complicated inserts. To insert new Movie, I need first to add new Production and second to insert Movie and pick just created Production ID.
My question is could it be fixed in some way ? Can't it be auto incremented from Movie table ?
I'm using 10.1.36-MariaDB and I'm realy sorry for my poor english :c
Since Movies and Series have only one column that is different (boxoffice), it makes sense to put the two tables together and let boxoffice be NULL for series. I don't understand the need for Production, but it seems to add as much complexity as it saves. Try to get rid of it.
I suggest that the id for Country be the standard 2-letter codes. This will be more compact and eliminate some stuff.
The is no good reason to have an id for a connection table. See many-to-many tips . Those tips will speed up many of your queries, and save space.
"Polymorphic" and many other neat-things-in-a-textbook don't necessarily work well in Relational Databases.

Automatically connect SQL tables based on keys

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.

How to implement a one-to-many relationship with an "Is Current" requirement

Designing a database, there's a relationship between two tables, Job and Document. One Job can have multiple Documents, but one (and only one) of these Documents needs to be flagged as IsCurrent. This is not always the most recent Document associated with that Job.
Structurally, I can see two ways of doing this.
The first is to add a DocumentId column to Job, and a JobId column to Document. This will work, but creates a circular reference: when imported into Entity Framework you end up with the peculiar situation that a Job has both a Document and a Documents collection. Likewise that Document has both a Job and a Jobs collection.
The second is to add an IsCurrent bit flag to the Document table. This will work, but leaves it logically possible for a Job to have multiple IsCurrent Documents, which is not allowed.
Questions:
1) Am I right in thinking there's no "third way" out of this dilemma?
2) Presuming not, which is better, and why? I favour the second solution as it seems much cleaner and we can enforce the single IsCurrent through the business logic. My colleague favours the former solution because it results in simpler C# code and object references - if we rename the foreign keys, it should avoid the confusion created by Job/Jobs.
If your back-end is SQL Server, you can create a filtered index to ensure that each job has at most one current document:
CREATE UNIQUE INDEX IX_Documents_Current
ON Documents (JobId) where IsCurrent=1
That way, it's not just enforced at the business level but is also enforced inside the database.
just for a third way (and for fun): consider using not a bit, but an int equals to max + 1 among the documents of the job.
then create a unique index on {job FK, said int}.
you can:
change current by updating the int,
get the current by searching the max and
prevent to have more than one current because of the unique index.
create a new non current document by using min - 1 for said int.
this is not the simplest to implement.
Yes there is a third way out of this dilemma. You need a DBMS that supports SQL's CREATE ASSERTION (and supports it correctly, of course). With such a DBMS, you can declare any data rule that applies to your situation and your DBMS will enforce that rule for you.
Unfortunately, no such DBMS exists * in the SQL world *. Outside of the SQL world, there are such engines. ASSERTIONs being my hobbyhorse, I wrote one myself. If you're interested, a Google search should lead you to it quickly.

How to effectively refresh many to many relationship

Lets say I have entity A, which have many to many relationship with another entities of type A. So on entity A, I have collection of A. And lets say I have to "update" this relationships according to some external service - from time to time I receive notification that relations for certain entity has changed, and array of IDs of current related entities - some relations can be new, some existing, some of existing no longer there... How can I effectively update my database with EF ?
Some ideas:
eager load entity with its related entities, do foreach on collection of IDs from external service, and remove/add as needed. But this is not very effective - need to load possibly hundreds of related entities
clear current relations and insert new. But how ? Maybe perform delete by stored procedure, and then insert by "fake" objects
a.Related.Add(new A { Id = idFromArray })
but can this be done in transaction ? (call to stored procedure and then inserts done by SaveChanges)
or is there any 3rd way ?
Thanx.
Well, "from time to time" does not sound like a situation to think much about performance improvement (unless you mean "from millisecond to millisecond") :)
Anyway, the first approach is the correct idea to do this update without a stored procedure. And yes, you must load all old related entities because updating a many-to-many relationship goes only though EFs change detection. There is no exposed foreign key you could leverage to update the relations without having loaded the navigation properties.
An example how this might look in detail is here (fresh question from yesterday):
Selecting & Updating Many-To-Many in Entity Framework 4
(Only the last code snippet before the "Edit" section is relevant to your question and the Edit section itself.)
For your second solution you can wrap the whole operation into a manually created transaction:
using (var scope = new TransactionScope())
{
using (var context = new MyContext())
{
// ... Call Stored Procedure to delete relationships in link table
// ... Insert fake objects for new relationships
context.SaveChanges();
}
scope.Complete();
}
Ok, solution found. Of course, pure EF solution is the first one proposed in original question.
But, if performance matters, there IS a third way, the best one, although it is SQL server specific (afaik) - one procedure with table-valued parameter. All new related IDs goes in, and the stored procedure performs delete and inserts in transaction.
Look for the examples and performance comparison here (great article, i based my solution on it):
http://www.sommarskog.se/arrays-in-sql-2008.html