Signum Framework Logo
"Open framework that encourages convention over configuration, using C# code,
not XML files, to model at the right level of abstraction and achieve deadlines.
...but also has a full Linq provider, and syncs the schema for you!"
Login
RSS

Search

»



Main
Index
Map
Videos
Download
Source code
Tutorials
Forum
FAQ



Image



PoweredBy


Introduction

We should have it clear now that in Signum Framework, entities rule. The database just reflects the structure of your entities and there's not a lot of room for customization.

There are, however, some situations where you have to enrich your entities with Database related information, like Indexes, specifying Scale and Precision for numbers, or use different string types in your DBMS.

We use .Net Attributes to specify this information. There's a lot of debate on the Web about using Attributes or XML files. But since we have agreed that we model using code instead of XML, this is not an issue for us. However, we have some points as to why we prefer not to use XML:

  • Cumbersome to use : Changing an XML is less convenient than changing code. Even with XSD the support is not that good. You can't test in XSD if a PropertyInfo exists in the .Net side. Since mapping entities to tables is all about Types and MemberInfos that means that your XML experience is going to be close to editing a file in Notepad. Also you will have the name of your Types and Fields in more than one place, and we don't like that.

  • Configuring the Framework, not your application: The best thing about Xml is that you can change the configuration in production code, without needing to recompile and not having an IDE available. Adding, removing or modifying tables and columns, however, is not something you should do without recompiling because very often this will change your logic. What you are really doing here is not configuring your application, but configuring the Signum Framework to be your application, and this is not something you should change in production code.

  • We allow to change mapping anyway: We agree, however, that not allowing any kind of change in the way entities are mapped will prevent some scenarios for reusing your entities code, specifically in Inheritance mappings, but also in indexes that make sense in some applications and not in others. We allow to change the Schema at runtime in a imperative type-safe fashion.

So, let's finish the debate and get to the point.

One important thing to remember:

Database customization --> FIELDS
Runtime Validations and Format --> PROPERTIES


Here we have the available Field Attributes:

IgnoreAttribute

Applied to field, prevent it from being a column and participating in any database related activity (Save, Retrieve, Queries...). Usually you need to calculate it after retrieving using PostRetrieve method.

Applied to a class prevent it from being found when using SchemaBuilder's IncludeSimilar or IncludeAll methods.

Easy!

NotNullableAttribute

Signum Framework expresses nullability of columns on the Database side by trying to reduce the type mismatch between .Net and SQL. So by default it will make columns of reference types nullables (i.e.String or any entity reference) and value types not nullable (i.e. int, DateTimes or GUIDs).

If you want to make a value type nullable just use Nullable or the more convenient syntax T?. But since there's no way to express non-nullability of reference types (we know that Anders is very sad about that) we need the NotNullableAttribute instead.

NotNullableAttribute, once applied over a field of a reference type, will make the related column not nullable.

Important Note: Signum Framework allows you to save arbitrary objects graphs. When a cycle of new object is found, you need to save inconsistent objects for a while, letting some FKs to be null until we know the actual Id of the related entity. If you use NotNullableAttribute over an Entity reference and something like this happens you will get an exception when saving. Don't use NotNullableAttribute on entity fields, use NotNullValidator on the property instead. See more about this in Database - Save

SqlDbTypeAttribute

Internally, Signum Engine follows the next tables to assign Sql Types to .Net Types

C# TypeSqlDbType
boolBit
byteTinyInt
shortSmallInt
intInt
longBigInt
floatReal
doubleFloat
decimalDecimal
charNChar
stringNVarChar
DateTimeDateTime
byte[]VarBinary
GuidUniqueIdentifier

SqlDbTypeSize/Precision
NVarChar200
Image8000
Binary8000
Char1
NChar1
Decimal18

SqlDbTypeScale
Decimal2

So by making a connection in your mind you can deduce that:

  string name; // NVARCHAR(200) NULL
  decimal price; // DECIMAL(18,2) NOT NULL

Sometimes, however, you want to modify this behaviour. You can do that using SqlDbType on any value field. It doesn't work on Entities fields, Lites or MList anything like that.

Notice that we trust that there's a conversion from your field type to your DbType, if you map a string to be a Bit column you will get a lot of exceptions.

Also, notice that if you change the SqlType then the default Size/Precision and Scale for the new type will be used, unless explicitly changed:

  [SqlDbType(SqlDbType=SqlDbType.NChar)]
  string name; // NCHAR(1) NULL
        
  [SqlDbType(SqlDbType=SqlDbType.NChar, Size = 100)]
  string name; // NCHAR(100) NULL

Finally, a very important note. SqlServer 2005 have deprecated NTEXT in favor of NVARCHAR(MAX). To achieve the MAX behaviour just use int.MaxValue as Size:

  [SqlDbType(Size = int.MaxValue)]
  string name; // NVARCHAR(MAX) NULL

Indexes

Indexes are a very important point of database design. By default, PrimaryKeys are indexed by MSSQL2005 but not on ForeignKeys.

The Schema holds a value Index for any column in your database, which can have the following values:

 public enum Index
 {
    None = 0,
    Unique,
    Multiple,
    UniqueMultiNulls
 }

This way, it's harder to create duplicate indexes over an item.

By default, Value types have Index.None, but since is a good idea to add multiple indexes on every ForeignKeys, the Schema will mark reference fields as Index.Multiple by default. If you want to override this behaviour, override DefaultReferenceIndex on your SchemaBuilder.

We will speak about Index.UniqueMultuNulls later.

NoIndexAttribute

Marks the field flag to Index.None, removing the index over a ForeignKey or any default indexed column in the future.

UniqueIndexAttribute

Marks the field flag to Index.Unique, creating a unique index on database.

If you use

        [UniqueIndex(AllowMultipleNulls=true)]
        string name;

then Index.UniqueMultiNullsis set, a trigger like this will be created:

CREATE  trigger {0} on {1} for insert, update as 
BEGIN  
    IF (select max(cnt) from 
            (select count(i.{2}) as cnt from {1}, inserted i where {1}.{2}=i.{2} group by i.{2}) x) > 1 
    raiserror('{3}',16,1) 
END

MultipleIndexAttribute

Marks the field flag to Index.Multiple, creating a multiple index to improve performance on value columns.

LowPopulationAttribute

Low population is characteristic of a Type, and is useful in the User Interface layer to place an EntityCombo instead of an EntityLine when picking filters in a Search window.

ImplementedBy & ImplementedByAll

See more about this in Inheritance

NotifyOnCollectionChangeAttribute & NotifyPropertyChangedAttribute

See about this in Change Tracking.



Creative Commons License Signum Framework Site by Signum Software is licensed under a Creative Commons Attribution 3.0 License.
Powered by ScrewTurn Wiki version 3.0.5.600.