June 19 Code Update

Jun 21, 2011 at 3:39 AM
Edited Mar 2, 2012 at 6:30 AM

Here's a list of fixes in the latest code update (06/19/2011)

  1. Cleaned up and fixed the schema update functionality. Now the functionality is much more reliable and consistent.
  2. Fixed one big annoyance in schema updates - adding non-nullable columns. If a new column is added to a table and it does not allow NULLs and has no default value (for ex, new non-nullable INT column), then the process goes in 3 steps. A new column is added as nullable, then existing records are updated and values in new columns are set to default value (0 for INTs); finally, the column is changed to non-nullable. In the future, I plan to add an ability to run a custom code to initialize the value in the added column. With this fix, I think the automatic schema update functionality becomes really USABLE.
  3. Properties now can have default values/expressions - these are translated into column default constraints in database.
  4. You can now create custom INSERT stored procedures/SQL commands from LINQ expressions. Previously you could do this only for SELECT, UPDATE, DELETE operations; now INSERT is supported as well. It allows you to insert a set of new records that is formed from some SELECT query.  
  5. Implemented correct algorithm for proper update sequencing - to take into account the referential constraints. The prior implementation was a simplistic substitute. Now the system performs the sequencing using the Strongly-Connected Components (SCC). More on this later, in a separate post.
  6. Computed columns - you can now define Entity property which is computed (derived) from other properties. For example, if Author entity has FirstName and LastName properties with corresponding columns in database table, you can define a FullName computed property and associate it with a computation method that returns (FirstName + " " + LastName) as a value. The computed property is marked by ComputedAttribute, and computation method is referenced through attribute parameters. Note that .NET does not allow to use references to methods as attribute parameters, so we use a workaround: a method is identified by a Type (defining class) method name (it must be a static method). Currently the method is invoked using Reflection, which is a bit slow - I plan to replace it with a compiled delegate call in the future. 
  7. Data validation on update. Entity data is now validated before submitting to database. The validation consists of 2 pieces. The first is automatic, system-provided validation of aspects derived from metadata, like missing non-nullable values, strings longer than column width, etc. The second part is custom validation, implemented by application code. You can specify the validation method for an entity using Validate attribute. This method will be invoked for every entity, after automatic validation. If entity is not valid, system throws a ValidationException, containing all validation errors for all entities in update pack. Look at a sample validation method for IBook entity in demo code to see how it works.    
  8. OrderBy for entities. You can now specify a default sort order for entity lists. You specify the order using OrderBy attribute on entity. It is appliced to queries that retrieve all entites (Session.GetAll method), and for list properties based on one-to-many relationships (like Publisher.Books property in Demo code). It does not work for many-to-many list properties (Ex: Book.Authors list), will fix it in the future. 
  9. Fixed/enforced the single-instance rule for entities/records. Whenever a certain record is loaded more than once in a single session, only one instance (.NET object) representing the record/entity exists in the context of the session, and all queries always return the same .NET object for the record. This was not enforced properly in previous version.  
  10. Removed EntityRegistry class and global dictionary that contained all entity definitions. It was used solely to initialize the entities that were created by direct LINQ queries. Using global values is not a good practice, so I decided to get rid of this registry. Now entities created in LINQ queries use temporary value container to store values assigned by LINQ engine as it reads database query results. Later, when entity comes out of the Linq2Sql engine, it is intercepted by a special proxy, which attaches it to the session and initializes it properly, replacing the temp container with DataRecord instance. 
  11. Numerous other fixes and refactorings. The code is cleaner, more clear and more stable now, that's for sure. 

That's not all - more info coming....