EditIntroduction
Database is the main façade of Signum Engine for normal operations with entities, like
saving,
retrieving,
querying and
deleting entities from the database. For administrative tasks, such as generating the schema or synchronizing it, we use the Database's sibling:
Administrator.
Three things that make Database class different to many other ORM façades:
EditDatabase class is static
No need to instantiate it, neither to pass it as a parameter or store it in some global variable. Client code (your code) is simpler and easier to re-use, while preserving flexibility to change the DB connection and the schema using
ConnectionScope.
Also, by being static, we can make some of the methods
extension methods over entities. So you have nice looking Save or Remove method on your entities when you are in the server, but without adding any dependency to the database, so you are still able not to send them to the client. This is really nice.
EditNo Code Generation
On Database class you will find general purpose methods to deal with IdentifiableEntity objects, also you will find generic overloading for an strong-typed way of programming. But what you are
not going to find there are properties, or methods overloads, to deal specifically with some concrete entity (i.e.: CustomerDN).
Doing something like that only makes sense if you are generating code (from database or an Xml file) and makes it really hard to reuse entities from one project to the next one. Also, by not doing it we save maintaining big xml (dbml, edmx ...).
Finally, no code generation makes the next point possible.
EditNo db-schema & code synchronization cycle while developing
Since Signum Framework is entirely based on entities, and they are written in C# code, you don't need to synchronize the database schema before doing the next step.
In fact, you could write the whole application from scratch without even having an SQL Server installed in the dev machine. Then, at the very end, you could install it, generate or resynchronize the schema using
Administrator, and test all your queries and code. It's not a very realistic scenario but it is possible to do it.
EditTo the point
Let's start with an example.
Suppose you have a very simplistic UserDN entity like this one:
[Serializable]
public class UserDN : Entity
{
[UniqueIndex]
string userName;
public string UserName
{
get { return userName; }
set { Set(ref userName, value, "UserName"); }
}
string passwordHash;
public string PasswordHash
{
get { return passwordHash; }
set { Set(ref passwordHash, value, "Password"); }
}
}
In case you don't know why the field is named passwordHash instead of password click
here
And you need to be able to change user's password, it would be implemented like this:
private static void ChangePassword(string userName, string oldPasswordHash, string newPasswordHash)
{
using (Transaction tr = new Transaction())
{
UserDN user = Database.Query<UserDN>().Single(a => a.UserName == userName);
if (user.PasswordHash != oldPasswordHash)
throw new ApplicationException("Incorrect password");
user.PasswordHash = newPasswordHash;
user.Save();
tr.Commit();
}
}
Looks easy, doesn't it?
This is what is actually happening:
- Transaction: We create a Transaction. Every atomic operation exposed by Database class is implicitily transactional, but by explicitly surrounding it with a Transaction object we are just making the transaction bigger.
- Query and Retrieve: We retrieve the only user with the provided username. Here we are using the integration of Linq queries with the retriever.
- Testing the old password (nothing to do with the framework really)
- Setting the new password, internally the Set method of the entity is called, so the entity becomes self modified.
- Save: Using
Database.Save<T>(this T obj) where T : IdentifiableEntity extension method to save the entity. You could write Database.Save(user) instead if you find it more clear. Also, in this example we're saving a simple entity but it could have a whole graph of related entities if necessary.