Hi Daniil,
thanks for your explanation about the isComplex property; I removed it from the recordfield definition, and the ServerMapping alone is working without problems.
About the intNT type and the objects I bind to the Store, i will try to explain you better what kind of classes i work with and the id null issue.
here is a definition for the xTLayer.NullTypes.intNT Type:
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace xTLayer
{
namespace Nulltypes
{
public class NullType : IComparable, IFormattable
{
protected object _value;
/// <summary>
/// IComparable.CompareTo implementation.
/// </summary>
public int CompareTo(object obj)
{
if (obj is NullType)
{
NullType temp = (NullType)obj;
return compare(this, temp);
}
throw new ArgumentException("object is not a NullType");
}
public static bool IsReallyNull(NullType n)
{
return (((object)n) == null || n._value == null);
}
private static System.Collections.Comparer _Comparer = new System.Collections.Comparer(System.Globalization.CultureInfo.CurrentCulture);
protected static int compare(NullType a, NullType b)
{
if (!isNull(a) && isNull(b))
return 1;
if (isNull(a) && !isNull(b))
return -1;
if (isNull(a) && isNull(b))
return 0;
return _Comparer.Compare(a._value, b._value);
}
protected static bool isNull(NullType a)
{
return (object)a == null || a._value == null || a._value.ToString() == "";
}
//public bool isNull {get { return _value == null;} set { if (value) _value = null; }}
public NullType()
{
_value = null;
}
public override int GetHashCode()
{
if (_value != null) return _value.GetHashCode();
return base.GetHashCode();
}
public static bool operator ==(NullType nt, NullType o)
{
return compare(nt, o) == 0;
}
public static bool operator !=(NullType nt, NullType o)
{
return compare(nt, o) != 0;
//return !(pi == o);
}
public static bool operator <(NullType nt, NullType o)
{
return compare(nt, o) < 0;
}
public static bool operator >(NullType nt, NullType o)
{
return compare(nt, o) > 0;
}
public static bool operator <=(NullType nt, NullType o)
{
return compare(nt, o) <= 0;
}
public static bool operator >=(NullType nt, NullType o)
{
return compare(nt, o) >= 0;
}
// public static bool IsNull(NullType pi)
// {
// return (((object)pi == null) || (pi.isNull)) ? true : false;
// }
// public static bool IsNull(object pi)
// {
// return (((object)pi == null) || (pi is System.DBNull) ) ? true : false;
// }
public static bool operator ==(NullType pi, object o)
{
try
{
// null null true
// null val false
// val null false
// val val confronto
if (((object)pi == null) || pi._value == null)
{
return ((o == null) || Convert.IsDBNull(o));
}
return ((o == null) || Convert.IsDBNull(o)) ? false : System.Convert.Equals(pi._value, o);
}
catch
{
return false;
}
}
public override bool Equals(object o)
{
if (o is NullType) return (this == (NullType)o);
else return (this == o);
}
public static bool operator !=(NullType pi, object o)
{
return !(pi == o);
}
/// <summary>
/// fa l'override del ToString. Se è nullo ritorna "" altrimenti passa al tostring del valore contenuto.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return this == null ? "" : _value.ToString();
}
public static implicit operator string(NullType nt)
{
return nt == null ? "" : nt._value.ToString();
}
/*public Object ObjectValue
{
get
{
return _value;
}
}*/
#region IFormattable Members
string System.IFormattable.ToString(string format, IFormatProvider formatProvider)
{
return _value == null ? "" : ((System.IFormattable)_value).ToString(format, formatProvider);
}
#endregion
}
public class IntNT : NullType, ISerializable, System.Xml.Serialization.IXmlSerializable, IFormattable
{
#region IXmlSerializable
public void WriteXml(System.Xml.XmlWriter writer)
{
if (_value != null)
writer.WriteString(this.ToString());
else writer.WriteAttributeString("null", "true");
}
public void ReadXml(System.Xml.XmlReader reader)
{
//if (reader.GetAttribute("null")!="true") // if (reader.HasValue)
if (reader.HasAttributes) // se ha attributi è nullo.
_value = null;
else
{
string str = reader.ReadString();
if (IsInt(str)) _value = Convert.ToInt32(str);
}
reader.ReadEndElement();
}
public System.Xml.Schema.XmlSchema GetSchema()
{
return (null);
}
#endregion
#region Serializable
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (_value != null)
info.AddValue("_value", Value);
}
private IntNT(SerializationInfo info, StreamingContext context)
{
if (info.MemberCount == 1)
{
_value = info.GetInt32("_value");
}
else _value = null;
}
#endregion
/// <summary>
/// IntNT nullo
/// </summary>
public IntNT()
{
_value = null;
}
/// <summary>
/// costruttore
/// </summary>
/// <param name="valore"></param>
public IntNT(object valore)
{
if (valore is IntNT)
{
_value = ((IntNT)valore)._value;
return;
}
if (null == valore || Convert.IsDBNull(valore) || valore.ToString() == "")
_value = null;
else
_value = Convert.ToInt32(valore);
}
/// <summary>
/// costruttore di copia
/// </summary>
/// <param name="IntNTObj"></param>
public IntNT(IntNT IntNTObj)
{
if (null == (object)IntNTObj)
_value = null;
else
_value = IntNTObj._value;
}
/// <summary>
/// Restituisce il valore intero
/// </summary>
public int Value
{
get
{
if (this._value == null) throw new System.NullReferenceException();
return Convert.ToInt32(_value);
}
/*set
{
_value = value;
} */
}
/// <summary>
/// converte dal tipo-base intero al tipo IntNT
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
public static implicit operator IntNT(int i)
{
return new IntNT((object)i);
}
/// <summary>
/// converte dal IntNT intero al tipo tipo-base
/// </summary>
/// <param name="o"></param>
/// <returns></returns>
public static implicit operator int(IntNT o)
{
return o.Value;
}
/// <summary>
/// converte il dbnull nel tipo IntNT
/// </summary>
/// <param name="dbn"></param>
/// <returns></returns>
public static implicit operator IntNT(System.DBNull dbn)
{
return new IntNT();
}
public static implicit operator IntNT(string str)
{
if (IsInt(str)) return new IntNT(Convert.ToInt32(str));
else return new IntNT();
}
// è intero solo se è numerico e senza virgola.
public static bool IsInt(string str)
{
if (str == null) return false;
return (str.IndexOf(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator) < 0); // && DecimalNT.IsNumeric(str)
}
#region IFormattable Members
public string ToString(string format, IFormatProvider formatProvider)
{
if (format != null)
{
if (format.IndexOf('|') > 0)
{
string[] split = format.Split('|');
for (int i = 0; i < split.Length; i++)
{
if (split[i].IndexOf('=') >= 0)
{
string[] split2 = split[i].Split('=');
if (base.ToString() == split2[0]) return split2[1];
}
}
}
return ((System.IFormattable)_value).ToString(format, formatProvider);
}
return base.ToString();
}
#endregion
}
}
}
As explained previously, we have built these types before the nullable came out, to easily handle the mapping between empty fields in web forms, and fields in the database.
So there's a NT type for int, decimal, string, boolean and so on.
After that we deployed custom classes and collections, whose properties are bound to the fields of a table using a DAL library.
You can look at it like a sort of very earlier Entity Framework, since we don't write these classes manually, of course; we wrote a code generator for that.
It connects to the db, let's you choose table and it generates custom classes, custom collections and CRUD and Find stored procedures.
so basicly a custom generated class lookes like this
PersonCollectionProvider prov = new PersonCollectionProvider() //used to populate the instance of a collection or class and manage db connection
Person employee = new Person();
PersonCollection employees = new PersonCollection();
class members are the NTTypes mapped to the table fields:
employee.IdXst23 (IntNT)
employee.Name (StringNT)
Classes and collections have methods to save, update and delete to the database.
So when I have a new record to insert, like in this case, I fill the object properties except for the Id, since it is mapped to an Identity column in the database, and call the method:
employee.Save();
//or, if I have more objects to save
employees.Add(employee);
emloyees.SaveCollection();
After saving the Id member is automatically populated from the db.
So of course the IdXst23 as Id property is null when I bind to the Store an object for a new record; it is never null for a DB retrieved instance or collection since the ID member is mapped to an identity Key Column.
I hope that the picture is more clear to you now, of course an id property can't be null, but when I insert a new record I don't have it since it should comes from the DB after insert.