123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Xml.Serialization;
- using System.Data;
- using System.IO;
- using System.Linq;
- using System.Collections;
- using EasyDevCore.Common;
- namespace EasyDevCore.Database.EntityTable
- {
- /// <summary>
- ///
- /// </summary>
- public enum DataTableSerializerSchema
- {
- /// <summary>
- /// The none
- /// </summary>
- None,
- /// <summary>
- /// The data table schema
- /// </summary>
- DataTableSchema,
- /// <summary>
- /// The column schema
- /// </summary>
- ColumnSchema
- }
- /// <summary>
- /// Convert DataTable to XML
- /// </summary>
- [Serializable]
- public class DataTableSerializer : IXmlSerializable
- {
- private DataTable _Table;
- private DataTableSerializerSchema _ProxySchema = DataTableSerializerSchema.None;
- private bool _ForSynchValues = false;
- private bool _OptimumSize = true;
- private string _KeyFields = string.Empty;
- private string _ColumnNames = string.Empty;
- private string _ExceptColumnNames = string.Empty;
- /// <summary>
- /// use for XmlSerialization
- /// </summary>
- private DataTableSerializer()
- {
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="DataTableSerializer" /> class.
- /// </summary>
- /// <param name="entities">The entities.</param>
- /// <param name="forSynchValues">if set to <c>true</c> [only changed values has been serialize for synchronized].</param>
- /// <param name="columnNames">The colum names filter (can be use = for mapping; ex: ColumnName = PropertyName).</param>
- /// <param name="exceptColumnNames">The except column names.</param>
- /// <param name="keyFields">The key fields.</param>
- /// <param name="proxySchema">The proxy schema.</param>
- /// <param name="optimumSize">if set to <c>true</c> [optimum size but slower].</param>
- public DataTableSerializer(DataTable entities, bool forSynchValues = false, string columnNames = "", string exceptColumnNames = "", string keyFields = "", DataTableSerializerSchema proxySchema = DataTableSerializerSchema.None, bool optimumSize = true)
- {
- _Table = entities;
- _ForSynchValues = forSynchValues;
- _ColumnNames = columnNames;
- _ExceptColumnNames = exceptColumnNames;
- _KeyFields = keyFields;
- _OptimumSize = optimumSize;
- _ProxySchema = proxySchema;
- if (proxySchema == DataTableSerializerSchema.None && entities != null)
- {
- _ProxySchema = DataTableSerializerSchema.DataTableSchema;
- }
- }
- /// <summary>
- /// Gets the table.
- /// </summary>
- /// <value>The entities.</value>
- public virtual DataTable Table
- {
- get
- {
- return _Table;
- }
- }
- #region IXmlSerializable Members
- /// <summary>
- /// This property is reserved, apply the <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"></see> to the class instead.
- /// </summary>
- /// <returns>
- /// An <see cref="T:System.Xml.Schema.XmlSchema"></see> that describes the XML representation of the object that is produced by the <see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"></see> method and consumed by the <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"></see> method.
- /// </returns>
- public System.Xml.Schema.XmlSchema GetSchema()
- {
- return null;
- }
- /// <summary>
- /// Gets the type of the entity collection.
- /// </summary>
- /// <returns></returns>
- public virtual Type GetDataTableType()
- {
- return null;
- }
- /// <summary>
- /// Loads the XML only for changes.
- /// </summary>
- /// <param name="reader">The reader.</param>
- /// <param name="optimumSize">if set to <c>true</c> [optimum size].</param>
- /// <param name="mapColumns">The map columns.</param>
- private void LoadXMLOnlyForSync(System.Xml.XmlReader reader, bool optimumSize, Dictionary<string, int> mapColumns)
- {
- DataRow row;
- DataColumn column;
- string rowState;
- while (reader.MoveToContent() == System.Xml.XmlNodeType.Element && reader.LocalName == "R")
- {
- row = Table.NewRow();
- rowState = reader.GetAttribute("rowStated");
- reader.ReadStartElement();
- while (reader.MoveToContent() != System.Xml.XmlNodeType.EndElement)
- {
- if (reader.LocalName == "CS") //Special columns
- {
- string[] colNuls = reader.GetAttribute("N").SplitCommaString();
- foreach (string col in colNuls)
- {
- column = Table.Columns[mapColumns["C" + col]];
- row[column.Ordinal] = DBNull.Value;
- }
- if (optimumSize)
- {
- string[] colZoEs = reader.GetAttribute("E").SplitCommaString();
- foreach (string col in colZoEs)
- {
- column = Table.Columns[mapColumns["C" + col]];
- row[column.Ordinal] = GetZeroOrEmptyValue(column.DataType);
- }
- }
- reader.Read();
- }
- else
- {
- column = Table.Columns[mapColumns[reader.LocalName]];
- row[column.Ordinal] = reader.ReadElementString().StringTo(column.DataType);
- }
- }
- Table.Rows.Add(row);
- switch (rowState)
- {
- case "Modified":
- row.AcceptChanges();
- row.SetModified();
- break;
- case "Deleted":
- row.Delete();
- break;
- }
- reader.ReadEndElement();
- }
- }
- /// <summary>
- /// Loads the XML all rows.
- /// </summary>
- /// <param name="reader">The reader.</param>
- /// <param name="optimumSize">if set to <c>true</c> [optimum size].</param>
- /// <param name="mapColumns">The map columns.</param>
- private void LoadXMLAllRows(System.Xml.XmlReader reader, bool optimumSize, Dictionary<string, int> mapColumns)
- {
- DataRow row;
- DataColumn column;
- while (reader.MoveToContent() == System.Xml.XmlNodeType.Element && reader.LocalName == "R")
- {
- row = Table.NewRow();
- reader.ReadStartElement();
- while (reader.MoveToContent() != System.Xml.XmlNodeType.EndElement)
- {
- if (reader.LocalName == "CS") //Special columns
- {
- string colNuls = reader.GetAttribute("N");
- if (!string.IsNullOrWhiteSpace(colNuls))
- {
- foreach (string col in colNuls.SplitCommaString())
- {
- column = Table.Columns[mapColumns["C" + col]];
- row[column.Ordinal] = DBNull.Value;
- }
- }
- if (optimumSize)
- {
- string colZoEs = reader.GetAttribute("E");
- if (!string.IsNullOrWhiteSpace(colZoEs))
- {
- foreach (string col in colZoEs.SplitCommaString())
- {
- column = Table.Columns[mapColumns["C" + col]];
- row[column.Ordinal] = GetZeroOrEmptyValue(column.DataType);
- }
- }
- }
- reader.Read();
- }
- else
- {
- column = Table.Columns[mapColumns[reader.LocalName]];
- row[column.Ordinal] = reader.ReadElementString().StringTo(column.DataType);
- }
- }
- Table.Rows.Add(row);
- reader.ReadEndElement();
- }
- Table.AcceptChanges();
- }
- /// <summary>
- /// Generates an object from its XML representation.
- /// </summary>
- /// <param name="reader">The <see cref="T:System.Xml.XmlReader"></see> stream from which the object is deserialized.</param>
- public void ReadXml(System.Xml.XmlReader reader)
- {
- bool forSynchValues = false;
- bool includeSchema = false;
- string type = string.Empty;
- string name = string.Empty;
- DataColumnCollection schemaColumns = null;
- reader.Read();
- if (reader.MoveToContent() == System.Xml.XmlNodeType.Element && reader.LocalName == "Option")
- {
- type = reader.GetAttribute("type");
- name = reader.GetAttribute("name");
- forSynchValues = reader.GetAttribute("forSynchValues").StringTo(false);
- includeSchema = reader.GetAttribute("includeSchema").StringTo(false);
- if (Table == null)
- {
- if (string.IsNullOrEmpty(type) && GetDataTableType() != null)
- {
- type = GetDataTableType().AssemblyQualifiedName;
- }
- if (string.IsNullOrEmpty(type))
- {
- type = typeof(DataTable).AssemblyQualifiedName;
- }
- _Table = (DataTable)ReflectionHelper.CreateInstance(type);
- if (!string.IsNullOrWhiteSpace(name)) _Table.TableName = name;
- }
- else
- {
- Table.Clear();
- }
- string[] extendedProperties = reader.GetAttribute("extendedProperties").Split(new char[] { ',', '|' }, StringSplitOptions.RemoveEmptyEntries);
- for (int i = 0; i < extendedProperties.Length; i = i + 2)
- {
- string attributeName = "extP_" + (i / 2).ToString();
- string value = reader.GetAttribute(attributeName);
- string typeName = extendedProperties[i + 1];
- string propertyName = extendedProperties[i];
- Table.ExtendedProperties[propertyName] = value.StringTo(extendedProperties[i + 1]);
- }
- reader.Read();
- }
- schemaColumns = Table.Columns;
- if (includeSchema)
- {
- if (reader.MoveToContent() == System.Xml.XmlNodeType.Element && reader.LocalName == "Schema")
- {
- string schemaType = reader.GetAttribute("type");
- if (schemaType == DataTableSerializerSchema.ColumnSchema.ToString())
- {
- reader.ReadStartElement();
- while (reader.MoveToContent() != System.Xml.XmlNodeType.EndElement)
- {
- DataColumn col = Table.Columns.Add(reader.LocalName, Type.GetType(reader.GetAttribute("type")));
- string defaultValue = reader.GetAttribute("defaultValue");
- col.DefaultValue = defaultValue == "<DBNull>" ? DBNull.Value : defaultValue.StringTo(col.DataType);
- reader.Read();
- }
- reader.ReadEndElement();
- }
- else //DataTable schema
- {
- string schema = reader.ReadInnerXml();
- if (!string.IsNullOrEmpty(schema))
- {
- using (StringReader sr = new StringReader(schema))
- {
- DataTable tempTable = new DataTable(name ?? "DataTable"); //Use only for get schema
- tempTable.ReadXmlSchema(sr);
- schemaColumns = tempTable.Columns;
- }
- using (StringReader sr = new StringReader(schema))
- {
- Table.ReadXmlSchema(sr);
- }
- }
- }
- }
- }
- Dictionary<string, int> mapColumns = new Dictionary<string, int>();
- foreach (DataColumn column in schemaColumns)
- {
- mapColumns.Add(string.Format("C{0}", column.Ordinal), Table.Columns[column.ColumnName].Ordinal);
- }
- if (forSynchValues)
- {
- LoadXMLOnlyForSync(reader, _OptimumSize, mapColumns);
- }
- else
- {
- LoadXMLAllRows(reader, _OptimumSize, mapColumns);
- }
- reader.ReadEndElement();
- }
- /// <summary>
- /// Determines whether [is zero or empty] [the specified value].
- /// </summary>
- /// <param name="value">The value.</param>
- /// <returns>
- /// <c>true</c> if [is zero or empty] [the specified value]; otherwise, <c>false</c>.
- /// </returns>
- protected bool IsZeroOrEmpty(object value)
- {
- Type type = value.GetType();
- if (type == typeof(string))
- {
- return (string)value == string.Empty;
- }
- else
- {
- if (type.IsNumericType())
- {
- return value.Equals(0);
- }
- }
- return false;
- }
- /// <summary>
- /// Gets the zero or empty value.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <returns></returns>
- protected object GetZeroOrEmptyValue(Type type)
- {
- if (type == typeof(string))
- {
- return string.Empty;
- }
- else
- {
- if (type.IsNumericType())
- {
- return 0;
- }
- }
- return string.Empty;
- }
- /// <summary>
- /// Creates the XML only for sync values.
- /// </summary>
- /// <param name="writer">The writer.</param>
- private void CreateXMLOnlyForSync(System.Xml.XmlWriter writer)
- {
- string[] exceptColNames = _ExceptColumnNames.SplitCommaString(trimSpace: true);
- string[] colNames = _ColumnNames.SplitCommaString(trimSpace: true);
- string[] keyFields = _KeyFields.SplitCommaString(trimSpace: true);
- Dictionary<int, string> columns = new Dictionary<int, string>();
- Dictionary<int, string> modifiedColumns = new Dictionary<int, string>();
- Dictionary<int, string> primaryKeysColumns = new Dictionary<int, string>();
- foreach (DataColumn column in Table.Columns)
- {
- if (string.IsNullOrEmpty(column.Expression) && !column.ReadOnly && (colNames.Length == 0 || Array.IndexOf(colNames, column.ColumnName) > -1)
- && (exceptColNames.Length == 0 || Array.IndexOf(exceptColNames, column.ColumnName) == -1))
- {
- string colName = string.Format("C{0}", column.Ordinal);
- columns.Add(column.Ordinal, colName);
- }
- }
- foreach (string columnName in keyFields)
- {
- int colNo = Table.Columns[columnName].Ordinal;
- string colName = string.Format("C{0}", Table.Columns[columnName].Ordinal);
- primaryKeysColumns.Add(colNo, colName);
- modifiedColumns.Add(colNo, colName);
- }
- DataView dataView = new DataView(Table, "", "", DataViewRowState.Added | DataViewRowState.Deleted | DataViewRowState.ModifiedCurrent);
- DataRow entity;
- foreach (DataRowView rowView in dataView)
- {
- entity = rowView.Row;
- writer.WriteStartElement("R");
- writer.WriteAttributeString("rowStated", entity.RowState.ToString());
- string colNuls = string.Empty;
- string colZeroOrEmpty = string.Empty;
- switch (entity.RowState)
- {
- case DataRowState.Added:
- foreach (KeyValuePair<int, string> column in columns)
- {
- if (!entity.IsNull(column.Key))
- {
- if (_OptimumSize && IsZeroOrEmpty(entity[column.Key]))
- {
- colZeroOrEmpty += !string.IsNullOrWhiteSpace(colZeroOrEmpty) ? "," + column.Key.ToString() : column.Key.ToString();
- }
- else
- {
- writer.WriteElementString(column.Value, entity[column.Key].StringFrom());
- }
- }
- else
- {
- colNuls += !string.IsNullOrWhiteSpace(colNuls) ? "," + column.Key.ToString() : column.Key.ToString();
- }
- }
- break;
- case DataRowState.Deleted:
- foreach (KeyValuePair<int, string> column in primaryKeysColumns)
- {
- writer.WriteElementString(column.Value, entity[column.Key, DataRowVersion.Original].StringFrom());
- }
- break;
- case DataRowState.Modified:
- //Saves only columns has value change
- if (!entity.IsChanged())
- {
- continue;
- }
- foreach (KeyValuePair<int, string> column in columns)
- {
- if (entity.IsChanged(column.Key))
- {
- if (!entity.IsNull(column.Key))
- {
- if (_OptimumSize && IsZeroOrEmpty(entity[column.Key]))
- {
- colZeroOrEmpty += !string.IsNullOrWhiteSpace(colZeroOrEmpty) ? "," + column.Key.ToString() : column.Key.ToString();
- }
- else
- {
- writer.WriteElementString(column.Value, entity[column.Key].StringFrom());
- }
- }
- else
- {
- colNuls += !string.IsNullOrWhiteSpace(colNuls) ? "," + column.Key.ToString() : column.Key.ToString();
- }
- }
- }
- break;
- }
- bool isNull = !string.IsNullOrWhiteSpace(colNuls);
- bool isZeroOrEmpty = !string.IsNullOrWhiteSpace(colZeroOrEmpty);
- if (isNull || isZeroOrEmpty)
- {
- writer.WriteStartElement("CS");
- if (isNull) writer.WriteAttributeString("N", colNuls);
- if (isZeroOrEmpty) writer.WriteAttributeString("E", colZeroOrEmpty);
- writer.WriteEndElement();
- }
- writer.WriteEndElement();
- }
- }
- /// <summary>
- /// Creates the XML all rows.
- /// </summary>
- /// <param name="writer">The writer.</param>
- private void CreateXMLAllRows(System.Xml.XmlWriter writer)
- {
- string[] exceptColNames = _ExceptColumnNames.SplitCommaString(trimSpace: true);
- string[] colNames = _ColumnNames.SplitCommaString(trimSpace: true);
- DataView dataView = new DataView(Table, "", "", DataViewRowState.CurrentRows);
- DataRow entity;
- Dictionary<int, string> columns = new Dictionary<int, string>();
- foreach (DataColumn column in Table.Columns)
- {
- if (string.IsNullOrEmpty(column.Expression) && !column.ReadOnly && (colNames.Length == 0 || Array.IndexOf(colNames, column.ColumnName) > -1)
- && (exceptColNames.Length == 0 || Array.IndexOf(exceptColNames, column.ColumnName) == -1))
- {
- columns.Add(column.Ordinal, string.Format("C{0}", column.Ordinal));
- }
- }
- foreach (DataRowView rowView in dataView)
- {
- entity = rowView.Row;
- writer.WriteStartElement("R");
- string colNuls = string.Empty;
- string colZeroOrEmpty = string.Empty;
- foreach (KeyValuePair<int, string> column in columns)
- {
- if (!entity.IsNull(column.Key))
- {
- if (_OptimumSize && IsZeroOrEmpty(entity[column.Key]))
- {
- colZeroOrEmpty += !string.IsNullOrWhiteSpace(colZeroOrEmpty) ? "," + column.Key.ToString() : column.Key.ToString();
- }
- else
- {
- writer.WriteElementString(column.Value, entity[column.Key].StringFrom());
- }
- }
- else
- {
- colNuls += !string.IsNullOrWhiteSpace(colNuls) ? "," + column.Key.ToString() : column.Key.ToString();
- }
- }
- bool isNull = !string.IsNullOrWhiteSpace(colNuls);
- bool isZeroOrEmpty = !string.IsNullOrWhiteSpace(colZeroOrEmpty);
- if (isNull || isZeroOrEmpty)
- {
- writer.WriteStartElement("CS");
- if (isNull) writer.WriteAttributeString("N", colNuls);
- if (isZeroOrEmpty) writer.WriteAttributeString("E", colZeroOrEmpty);
- writer.WriteEndElement();
- }
- writer.WriteEndElement();
- }
- }
- /// <summary>
- /// Converts an object into its XML representation.
- /// </summary>
- /// <param name="writer">The <see cref="T:System.Xml.XmlWriter"></see> stream to which the object is serialized.</param>
- public void WriteXml(System.Xml.XmlWriter writer)
- {
- writer.WriteStartElement("Option");
- writer.WriteAttributeString("name", Table.TableName);
- writer.WriteAttributeString("includeSchema", (_ProxySchema != DataTableSerializerSchema.None).ToString());
- writer.WriteAttributeString("type", _ProxySchema != DataTableSerializerSchema.None ? string.Empty : Table.GetType().AssemblyQualifiedName);
- writer.WriteAttributeString("forSynchValues", _ForSynchValues.ToString());
- writer.WriteAttributeString("optimumSize", _OptimumSize.ToString());
- string extendedProperites = string.Empty;
- int p = 0;
- foreach (DictionaryEntry prop in Table.ExtendedProperties)
- {
- extendedProperites += (!string.IsNullOrWhiteSpace(extendedProperites) ? "," : string.Empty) + prop.Key + "|" + prop.Value.GetType().FullName;
- writer.WriteAttributeString("extP_" + p++.ToString(), prop.Value.StringFrom());
- }
- writer.WriteAttributeString("extendedProperties", extendedProperites);
- writer.WriteEndElement();
- if (_ProxySchema != DataTableSerializerSchema.None)
- {
- writer.WriteStartElement("Schema");
- if (_ProxySchema == DataTableSerializerSchema.DataTableSchema)
- {
- Table.WriteXmlSchema(writer);
- }
- if (_ProxySchema == DataTableSerializerSchema.ColumnSchema)
- {
- writer.WriteAttributeString("type", _ProxySchema.ToString());
- foreach (DataColumn col in Table.Columns)
- {
- writer.WriteStartElement(col.ColumnName);
- writer.WriteAttributeString("type", col.DataType.FullName);
- writer.WriteAttributeString("defaultValue", col.DefaultValue == DBNull.Value ? "<DBNull>" : col.DefaultValue.ToString());
- writer.WriteEndElement();
- }
- }
- writer.WriteEndElement();
- }
- if (_ForSynchValues)
- {
- CreateXMLOnlyForSync(writer);
- }
- else
- {
- CreateXMLAllRows(writer);
- }
- }
- #endregion
- }
- }
|