private DomainModel LoadDomain()
        {
            var path = GetXmlPath();

            if (File.Exists(path))
            {
                XmlDocument xml = new XmlDocument();
                xml.Load(path);
                var ser = new DomainModelSerializer();
                return(ser.Deserialize(xml));
            }
            else
            {
                return(new DomainModel());
            }
        }
        public void Save(DomainModel dm)
        {
            //ensure relations
            foreach (var em in dm.Entities)
            {
                foreach (var rel in em.Relations)
                {
                    if (!dm.Relations.Contains(rel.Name))
                    {
                        dm.Relations.Add(rel);
                    }
                }
            }

            List <Table> tables = new List <Table>();

            foreach (var entity in dm.Entities)
            {
                foreach (var listener in _changeListeners)
                {
                    listener.BeforeSave(entity);
                }

                Table tbl = new Table(entity.Name);
                foreach (var prop in entity.Properties)
                {
                    if (prop is StringPropertyModel)
                    {
                        tbl.Columns.Add(CreateStringColumn(prop as StringPropertyModel));
                    }
                    else if (prop is NumberPropertyModel)
                    {
                        tbl.Columns.Add(CreateNumberPropertyColumn(prop as NumberPropertyModel));
                    }
                    else if (prop is BooleanPropertyModel)
                    {
                        tbl.Columns.Add(CreateBooleanPropertyModel(prop as BooleanPropertyModel));
                    }
                    else if (prop is EnumPropertyModel)
                    {
                        tbl.Columns.Add(CreateEnumPropertyColumn(prop as EnumPropertyModel));
                    }
                    else if (prop is SequencePropertyModel)
                    {
                        tbl.Columns.Add(CreateSequencePropertyColumn(prop as SequencePropertyModel));
                    }
                    else if (prop is ComputedPropertyModel)
                    {
                        tbl.Columns.Add(CreateComputedPropertyColumn(prop as ComputedPropertyModel));
                    }
                    else if (prop is DateTimePropertyModel)
                    {
                        tbl.Columns.Add(CreateDateTimePropertyColumn(prop as DateTimePropertyModel));
                    }

                    if (prop.DefaultValue != null)
                    {
                        tbl.Constraints.Add(new DefaultConstraint(entity.Name, prop.Name, GetDefaultValueForProperty(prop)));
                    }
                }

                foreach (var rule in entity.Rules)
                {
                    if (rule is RequiredRuleModel)
                    {
                        var rr  = rule as RequiredRuleModel;
                        var col = tbl.Columns.Find(c => c.Name.Equals(rr.Property.Name, StringComparison.InvariantCultureIgnoreCase));
                        col.IsNullable = false;
                    }
                    else if (rule is UniqueRuleModel)
                    {
                        var ur = rule as UniqueRuleModel;
                        tbl.Constraints.Add(new UniqueConstraint(tbl.Name, ur.Properties.Select(p => p.Name).ToArray()));
                    }
                    else if (rule is FutureOrPastDateRuleModel)
                    {
                        continue;
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                }

                tbl.Constraints.Add(new Sql.Constraint(string.Format("PK_{0}", tbl.Name), Sql.Constraint.PRIMARY_KEY, "Id"));
                tables.Add(tbl);
            }

            foreach (var rel in dm.Relations)
            {
                Table tbl = new Table(rel.Name);
                //TODO
                ModelBuilder mb = new ModelBuilder(rel);
                if (!rel.Properties.Contains("id"))
                {
                    mb.AddIdentity("id");
                }
                if (!rel.Properties.Contains("lid"))
                {
                    mb.AddInteger("lid");
                    mb.Rules.AddRequired("lid");
                }
                if (!rel.Properties.Contains("rid"))
                {
                    mb.AddInteger("rid");
                    mb.Rules.AddRequired("rid");
                }

                if (rel.Type == RelationType.OneToOne)
                {
                    mb.Rules.AddUnique("lid");
                    mb.Rules.AddUnique("rid");
                }

                foreach (var prop in rel.Properties)
                {
                    if (prop is StringPropertyModel)
                    {
                        tbl.Columns.Add(CreateStringColumn(prop as StringPropertyModel));
                    }
                    else if (prop is NumberPropertyModel)
                    {
                        tbl.Columns.Add(CreateNumberPropertyColumn(prop as NumberPropertyModel));
                    }
                    else if (prop is BooleanPropertyModel)
                    {
                        tbl.Columns.Add(CreateBooleanPropertyModel(prop as BooleanPropertyModel));
                    }
                    else if (prop is EnumPropertyModel)
                    {
                        tbl.Columns.Add(CreateEnumPropertyColumn(prop as EnumPropertyModel));
                    }
                    else if (prop is SequencePropertyModel)
                    {
                        tbl.Columns.Add(CreateSequencePropertyColumn(prop as SequencePropertyModel));
                    }
                    else if (prop is ComputedPropertyModel)
                    {
                        tbl.Columns.Add(CreateComputedPropertyColumn(prop as ComputedPropertyModel));
                    }
                    else if (prop is DateTimePropertyModel)
                    {
                        tbl.Columns.Add(CreateDateTimePropertyColumn(prop as DateTimePropertyModel));
                    }

                    if (prop.DefaultValue != null)
                    {
                        tbl.Constraints.Add(new DefaultConstraint(rel.Name, prop.Name, GetDefaultValueForProperty(prop)));
                    }
                }

                foreach (var rule in rel.Rules)
                {
                    if (rule is RequiredRuleModel)
                    {
                        var rr  = rule as RequiredRuleModel;
                        var col = tbl.Columns.Find(c => c.Name.Equals(rr.Property.Name, StringComparison.InvariantCultureIgnoreCase));
                        col.IsNullable = false;
                    }
                    else if (rule is UniqueRuleModel)
                    {
                        var ur = rule as UniqueRuleModel;
                        tbl.Constraints.Add(new UniqueConstraint(rel.Name, ur.Properties.Select(p => p.Name).ToArray()));
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                }

                switch (rel.Type)
                {
                case RelationType.OneToOne:
                    tbl.Constraints.Add(new Sql.Constraint(string.Format("PK_{0}", tbl.Name), Sql.Constraint.PRIMARY_KEY, "LID", "RID"));
                    break;

                case RelationType.OneToMany:
                    tbl.Constraints.Add(new Sql.Constraint(string.Format("PK_{0}", tbl.Name), Sql.Constraint.PRIMARY_KEY, "RID"));
                    break;

                case RelationType.ManyToOne:
                    tbl.Constraints.Add(new Sql.Constraint(string.Format("PK_{0}", tbl.Name), Sql.Constraint.PRIMARY_KEY, "LID"));
                    break;

                case RelationType.ManyToMany:
                    tbl.Constraints.Add(new Sql.Constraint(string.Format("PK_{0}", tbl.Name), Sql.Constraint.PRIMARY_KEY, "LID", "RID"));
                    break;

                default:
                    throw new NotImplementedException("Unknown RelationType.");
                }

                tbl.Constraints.Add(new Sql.ForeignKeyConstraint(string.Format("FK_{0}_{1}", tbl.Name, rel.Left.Name), new string[] { "LID" }, rel.Left.Name, new string[] { "Id" }));
                tbl.Constraints.Add(new Sql.ForeignKeyConstraint(string.Format("FK_{0}_{1}", tbl.Name, rel.Right.Name), new string[] { "RID" }, rel.Right.Name, new string[] { "Id" }));

                tables.Add(tbl);
            }

            using (SqlConnection conn = _dbService.GetSqlConnection())
            {
                conn.Open();
                //TODO: transaction
                //var tran = conn.BeginTransaction(System.Data.IsolationLevel.Serializable);
                DatabaseManager mgr = new DatabaseManager(conn);
                mgr.Merge(tables, null);
                //tran.Commit();
            }

            DomainModelSerializer ser = new DomainModelSerializer();

            ser.Serialize(dm).Save(GetXmlPath());
            _domain = null;
        }