Example #1
0
        /// <summary>Add a new column to the DB.</summary>
        /// <remarks>
        /// <para>The column must exist in the record's type.</para>
        /// <para>If you're creating a column that's no longer in the schema (because you're doing a sequential upgrade step to the non-latest version),
        /// you better leave the column + attribute in the record class, but mark it with <see cref="System.ObsoleteAttribute">[Obsolete]</see> attribute.</para>
        /// </remarks>
        /// <typeparam name="tRow">Record type</typeparam>
        /// <param name="name">Name of the ESENT column to add</param>
        public void AddColumn <tRow>(string name) where tRow : new()
        {
            TypeSerializer ser = serializerForType(typeof(tRow));

            TypeSerializer.ColumnInfo ci = ser.getColumnsSchema().FirstOrDefault(c => c.columnName == name);
            if (null == ci)
            {
                throw new SerializationException("The column '" + name + "' was not found on row type '" + typeof(tRow).Name + "'.");
            }

            Action act = () =>
            {
                JET_TABLEID idTable;
                Api.JetOpenTable(this.session.idSession, this.session.idDatabase, ser.tableName, null, 0, OpenTableGrbit.None, out idTable);
                try
                {
                    JET_COLUMNID idColumn;
                    Api.JetAddColumn(this.session.idSession, idTable, ci.columnName, ci.attrib.getColumnDef(), null, 0, out idColumn);

                    if (!ci.attrib.bFieldNullable)
                    {
                        // The new column is not nullable.
                        // It means attempts to de-serialize the column will throw saying "Nullable object must have a value"
                        // To fix, we update all records of the table, setting the default value of the column.

                        // TODO: instead of creating default value for type, use reflection to find out is there a default value in the record class
                        object objVal = Activator.CreateInstance(ci.tpValue);

                        Cursor <tRow> cur = new Cursor <tRow>(this.session, ser, idTable, false);
                        if (cur.TryMoveFirst())
                        {
                            do
                            {
                                cur.SaveSingleField(ci.columnName, objVal);
                                // TODO [low]: pulse the transaction here.. The version store can be exhausted for large tables.
                            }while(cur.tryMoveNext());
                        }
                    }
                }
                finally
                {
                    Api.JetCloseTable(this.session.idSession, idTable);
                }
            };

            this.actUpgrade += act;
        }
Example #2
0
        int Import(TextReader tr)
        {
            string line;

            // Header; we also trim that extra trailing tabs being appended by Excel when saving documents in the TSV format.
            line = tr.ReadLine().TrimEnd(s_cTab);
            if (line != this.GetType().FullName)
            {
                throw new SerializationException("Wrong signature: stored " + line + ", must be " + this.GetType().FullName + ".");
            }
            line = tr.ReadLine().TrimEnd(s_cTab);
            int cols = int.Parse(line);

            if (schema.Count != cols)
            {
                throw new SerializationException("Wrong columns count: stored " + cols + ", must be " + schema.Count + ".");
            }

            // Validate the stored columns schema.
            JET_COLUMNDEF[] arrCd = new JET_COLUMNDEF[cols];
            string[]        arr;
            for (int i = 0; i < cols; i++)
            {
                TypeSerializer.ColumnInfo ci = schema[i];
                JET_COLUMNDEF             cd = ci.attrib.getColumnDef();
                arrCd[i] = cd;

                line = tr.ReadLine();
                arr  = line.Split(new char[] { '\t' });
                if (arr[0] != ci.columnName)
                {
                    throw new SerializationException("Wrong column name: stored '" + arr[0] + "', must be '" + ci.columnName + "'.");
                }

                eColumnKind ck = (eColumnKind)(Enum.Parse(typeof(eColumnKind), arr[1]));
                if (ck != ci.attrib.getColumnKind())
                {
                    throw new SerializationException("Wrong column kind: stored '" + ck.ToString() + "', must be '" + ci.attrib.getColumnKind().ToString() + "'.");
                }

                if (cd.coltyp != (JET_coltyp)(int.Parse(arr[2])))
                {
                    throw new SerializationException("Mismatched type of column '" + ci.columnName + "'");
                }
                if (cd.cp != (JET_CP)(int.Parse(arr[3])))
                {
                    throw new SerializationException("Mismatched codepage of column '" + ci.columnName + "'");
                }
                if (cd.grbit != (ColumndefGrbit)(int.Parse(arr[4])))
                {
                    throw new SerializationException("Mismatched bit flags of column '" + ci.columnName + "'");
                }
            }

            // Import the rows.
            return(ImportData
                   (
                       ( int nRecord ) =>
            {
                line = tr.ReadLine();
                return line != null;
            },
                       ( int nRecord ) =>
            {
                if (line == "")
                {
                    return false;
                }
                arr = line.Split(s_cTab);
                if (arr.Length < cols)
                {
                    throw new SerializationException("Too few columns in the line '" + line + "'");
                }
                for (int i = 0; i < cols; i++)
                {
                    JET_COLUMNDEF cd = arrCd[i];
                    if (0 != (cd.grbit & ColumndefGrbit.ColumnAutoincrement))
                    {
                        // TODO: look for a way to restore ColumnAutoincrement values.
                        continue;
                    }

                    if (!isMultiValued(cd))
                    {
                        LoadVal(arr[i], schema[i].idColumn, cd.coltyp, cd.cp);
                    }
                    else
                    {
                        string[] arr2 = arr[i].Split(s_cSlash);
                        foreach (string item in arr2)
                        {
                            LoadVal(item, schema[i].idColumn, cd.coltyp, cd.cp);
                        }
                    }
                }
                return true;
            }
                   ));
        }
Example #3
0
        int Export(TextWriter tw)
        {
            int cols = schema.Count;

            // Header
            tw.WriteLine(this.GetType().FullName);
            tw.WriteLine(cols);

            // Columns schema
            JET_COLUMNDEF[] arrCd = new JET_COLUMNDEF[cols];
            string[]        arr;
            for (int i = 0; i < cols; i++)
            {
                TypeSerializer.ColumnInfo ci = schema[i];
                JET_COLUMNDEF             cd = ci.attrib.getColumnDef();
                arrCd[i] = cd;

                arr = new string[]
                {
                    ci.columnName,
                    ci.attrib.getColumnKind().ToString(),
                    ((int)cd.coltyp).ToString(),
                    ((int)cd.cp).ToString(),
                    ((int)cd.grbit).ToString(),
                };
                tw.WriteLine(string.Join("\t", arr));
            }

            // Rows
            arr = new string[cols];
            return(ExportData
                   (
                       ( int nRecord ) =>
            {
                for (int i = 0; i < cols; i++)
                {
                    JET_COLUMNDEF cd = arrCd[i];

                    if (isMultiValued(cd))
                    {
                        for (int j = 1; true; j++)
                        {
                            string val = getStringValue(tw, schema[i].idColumn, j, cd.coltyp, cd.cp);
                            if (val == "")
                            {
                                break;
                            }
                            if (j > 1)
                            {
                                tw.Write('/');
                            }
                            tw.Write(val);
                        }
                    }
                    else
                    {
                        string val = getStringValue(tw, schema[i].idColumn, 1, cd.coltyp, cd.cp);
                        tw.Write(val);
                    }
                    if (i + 1 < cols)
                    {
                        tw.Write('\t');
                    }
                }
                tw.WriteLine();
            }
                   ));
        }