--- /dev/null
+# Azure Federations\r
+\r
+Implementing Federations inside a new Doctrine Sharding Extension. Some extensions to the DBAL and ORM core have to be done to get this working.\r
+\r
+1. DBAL (Database Abstraction Layer)\r
+\r
+* Add support for Database Schema Operations\r
+ * CREATE FEDERATION\r
+ * CREATE TABLE ... FEDERATED ON\r
+ * Add support to create a multi-tenent schema from any given schema\r
+* Add API to pick a shard based on distribution key and atomic value\r
+* Add API to ask about federations, federation members and so on.\r
+* Add Sharding Abstraction\r
+ * If a shard is picked via distribution key and atomic value fire queries against this only\r
+ * Or query the global database.\r
+\r
+2. ORM (Object-Relational Mapper)\r
+\r
+* Federation Key has to be part of the clustered index of the table\r
+ * Test with a pure Multi-Tenent App with Filtering = ON (TaskList)\r
+ * Test with sharded app (Weather)\r
+\r
+## Implementation Details\r
+\r
+SQL Azure requires one and exactly one clustered index. It makes no difference if the primary key\r
+or any other key is the clustered index. Sharding requires an external ID generation (no auto-increment)\r
+such as GUIDs. GUIDs have negative properties with regard to clustered index performance, so that\r
+typically you would add a "created" timestamp for example that holds the clustered index instead\r
+of making the GUID a clustered index.\r
+\r
+## Example API:\r
+\r
+ @@@ php\r
+ <?php\r
+ use Doctrine\DBAL\DriverManager;\r
+\r
+ $dbParams = array(\r
+ 'dbname' => 'tcp:dbname.database.windows.net',\r
+ 'sharding' => array(\r
+ 'federationName' => 'Orders_Federation',\r
+ 'distributionKey' => 'CustID',\r
+ 'distributionType' => 'integer',\r
+ 'filteringEnabled' => false,\r
+ ),\r
+ // ...\r
+ );\r
+\r
+ $conn = DriverManager::getConnection($dbParams);\r
+ $shardManager = $conn->getShardManager();\r
+\r
+ // Example 1: query against root database\r
+ $sql = "SELECT * FROM Products";\r
+ $rows = $conn->executeQuery($sql);\r
+\r
+ // Example 2: query against the selected shard with CustomerId = 100\r
+ $aCustomerID = 100;\r
+ $shardManager->selectShard($aCustomerID); // Using Default federationName and distributionKey\r
+ // Query: "USE FEDERATION Orders_Federation (CustID = $aCustomerID) WITH RESET, FILTERING OFF;"\r
+\r
+ $sql = "SELECT * FROM Customers";\r
+ $rows = $conn->executeQuery($sql);\r
+\r
+ // Example 3: Reset API to root database again\r
+ $shardManager->selectGlobal();\r
+\r
+## ID Generation\r
+\r
+With sharding all the ids have to be generated for global uniqueness. There are three strategies for this.\r
+\r
+1. Use GUIDs as described here http://blogs.msdn.com/b/cbiyikoglu/archive/2011/06/20/id-generation-in-federations-identity-sequences-and-guids-uniqueidentifier.aspx\r
+2. Having a central table that is accessed with a second connection to generate sequential ids\r
+3. Using natural keys from the domain.\r
+\r
+The second approach has the benefit of having numerical primary keys, however also a central failure location. The third strategy can seldom be used, because the domains dont allow this. Identity columns cannot be used at all.\r
+\r
+ @@@ php\r
+ <?php\r
+ use Doctrine\DBAL\DriverManager;\r
+ use Doctrine\DBAL\Id\TableHiLoIdGenerator;\r
+\r
+ $dbParams = array(\r
+ 'dbname' => 'dbname.database.windows.net',\r
+ // ...\r
+ );\r
+ $conn = DriverManager::getConnection($dbParams);\r
+\r
+ $idGenerator = new TableHiLoIdGenerator($conn, 'id_table_name', $multiplicator = 1);\r
+ // only once, create this table\r
+ $idGenerator->createTable();\r
+\r
+ $nextId = $idGenerator->generateId('for_table_name');\r
+ $nextOtherId = $idGenerator->generateId('for_other_table');\r
+\r
+The connection for the table generator has to be a different one than the one used for the main app to avoid transaction clashes.\r