Ok, I've implemented a class MultiSplitStringType : IUserType,
IParameterizedType where the idea is to set 2 parameters to the
mapping, "splitLength" tells the usertype at which character count to
split the string, "numColumns" tells the usertype how many columns in
the DB to map to. I couldn't get the IParameterizedType mapping to
work with Fluent nHibernate so that part is hardcoded to
splitLength=70 and numColumns=4 at the moment.

The MultiSplitStringType mapping does not work as expected though. I
map this in an entity at the many side of a many-to-one relationship
and when there are more than one item in the collection this happens:

If the first item in the collection has it's MultiSplitStringType
property set to a string with 70 < Length < 140 it correctly splits
the string in 2 parts and updates the database correctly. However, the
second item in the collection (second row in DB) also gets updated,
but only the second column of the mapping. If anyone can give me any
insight to this issue, please help. Code is below:

TEST CODE:
        [TestMethod]
        public void
ShipmentRepository_GetDataFromDB_ShouldMapCorrectly()
        {
            ShipmentRepository shipRep = new ShipmentRepository();
            ShipmentDocsBase sdb =
shipRep.GetShipmentDocsBaseById(126851);
            List<AesPackage> packages =
sdb.Aes.AesPackages.ToList<AesPackage>();
// FIRST RESET DATA IN DB
            packages[0].F31Description = "Teile fuer elektrische
Wohnraumleuchten aus unedlem Metall";
            packages[1].F31Description = "Testproduct 1, one line
only";
            shipRep.SaveShipmentDocsBase(sdb);
// All is correct at this point in DB

// SET F31Description of first item in Aes.AesPackages collection to a
string that will be split in 2 parts
            packages[0].F31Description =
"1234567890123456789012345678901234567890123456789012345678901234567890Next
part of description";
            shipRep.SaveShipmentDocsBase(sdb);
// After writing to DB:
//AES_PACKAGE_ID  , AES_ID,
F31_DESC1                                                                ,
F31_DESC2                 , F31_DESC3, F31_DESC4
//252109          , 121435,
'1234567890123456789012345678901234567890123456789012345678901234567890' ,
'Next part of description', ''       , ''
//252110          , 121435, 'Testproduct 1, one line
only'                                           , 'Next part of
description', ''       , ''
// WRONG, only first row should have F31_DESC2 set to 'Next part of
description'
        }

CLASS AesPackage (the MANY part in relationship):
        private Aes _aes;
        private Nullable<System.Int64> _actorId;
        private System.String _f31Description;
        public virtual System.Int64 AesPackageId
        {
                get { return _aesPackageId; }
        }
        public virtual System.String F31Description
        {
            get { return _f31Description; }
            set { _f31Description = value; }
        }

CLASS Aes ("parent"):
        private ICollection<AesPackage> _aesPackages;
        private System.Int64 _aesId;
        public virtual System.Int64 AesId
        {
                get { return _aesId; }
        }
        public virtual ICollection<AesPackage> AesPackages
        {
            get { return _aesPackages; }
            set { _aesPackages = value; }
        }


MAPPING AesPackage:
        public AesPackageMap()
        {
                        Table("`aes_packages`");
                        OptimisticLock.None();
                        //LazyLoad();

                        Id(x=>x.AesPackageId)
                                .Access.CamelCaseField(Prefix.Underscore)
                                .Column("AES_PACKAGE_ID")
                                .GeneratedBy.Identity();
            Map(x => x.F31Description)
                .Columns.Clear()
                .Columns.Add("F31_DESC1")
                .Columns.Add("F31_DESC2")
                .Columns.Add("F31_DESC3")
                .Columns.Add("F31_DESC4")
                .CustomType(typeof(MultiSplitStringType));

                        References(x=>x.Aes)
                                .Access.CamelCaseField(Prefix.Underscore)
                                .Cascade.All()
                                .Fetch.Select()
                                .Columns.Add("AES_ID");

MAPPING Aes:
        public AesMap()
        {
                        Table("`aes`");
                        OptimisticLock.None();
                        //LazyLoad();

                        Id(x=>x.AesId)
                                .Access.CamelCaseField(Prefix.Underscore)
                                .Column("AES_ID")
                                .GeneratedBy.Identity();
            HasMany(x => x.AesPackages)
                .Access.CamelCaseField(Prefix.Underscore)
                .Cascade.AllDeleteOrphan()
                .Fetch.Select()
                .AsSet()
                .Inverse()
                //.LazyLoad()
                .Key(ke => ke.Columns.Add("AES_ID"));


USERTYPE:
    [Serializable]
    public class MultiSplitStringType : IUserType //,
IParameterizedType
    {
        int _splitLength = 70;
        int _numColumns = 4;

        public SqlType[] SqlTypes
        {
            get
            {
                SqlType[] sqlTypesToReturn = new SqlType[_numColumns];
                for (int i = 0; i < sqlTypesToReturn.Length; i++)
                {
                    sqlTypesToReturn[i] = new StringSqlType();
                }

                return sqlTypesToReturn;
                //return new SqlType[] { new StringSqlType(), new
StringSqlType(), new StringSqlType(), new StringSqlType() };
            }
        }

        public Type ReturnedType
        {
            get { return typeof(string); }
        }

        public new bool Equals(object x, object y)
        {
            if (x == y) return true;
            if (x == null || y == null) return false;
            return ((string)x).Equals((string)y);
        }

        public int GetHashCode(object x)
        {
            return x.GetHashCode();
        }

        public Object DeepCopy(Object x)
        {
            if (x == null) return null;
            return x.ToString();
        }

        public bool IsMutable
        {
            get { return true; }
        }

        public Object NullSafeGet(IDataReader rs, string[] names,
Object owner)
        {
            StringBuilder sb = new StringBuilder();
            string s;
            for (int i = 0; i < names.Length; i++)
            {
                s = (string)NHibernateUtil.String.NullSafeGet(rs,
names[i]);
                if (s == null)
                {
                    if (i == 0)
                        return null;
                    break;
                }
                sb.Append(s);
            }

            return sb.ToString();
        }


        public void NullSafeSet(IDbCommand st, Object value, int
index)
        {
            if (_splitLength == 0)
                throw new Exception ("UserType MultiSplitStringType
requres parameter 'splitLength' to be set to a valid integer > 0.");

            if (value == null || value == DBNull.Value)
            {
                for (int i = index; i < (index + _numColumns); i++)
                {
                    NHibernateUtil.String.NullSafeSet(st, null,
index);
                }
            }

            string[] strings = TextUtils.StringSplit(value.ToString(),
_splitLength);

            //if (strings.Length > _numColumns)
            //    throw new Exception("Property value in UserType
MultiSplitStringType cannot be mapped to DB columns because number of
split strings exceed number of columns in mapping");

            for (int i = index; i < (strings.Length + index); i++)
            {
                NHibernateUtil.String.NullSafeSet(st, strings[i -
index], i);
            }
        }

        public object Assemble(
            object cached,
            object owner)
        {
            return DeepCopy(cached);
        }

        public object Disassemble(Object value)
        {
            return DeepCopy(value);
        }

        public object Replace(object original, object target, object
owner)
        {
            return DeepCopy(original);
        }


On 7 Okt, 13:30, Fabio Maulo <[email protected]> wrote:
> IUserType implemented as multicolumn type.
>
> --
> Fabio Maulo

-- 
You received this message because you are subscribed to the Google Groups 
"nhusers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/nhusers?hl=en.

Reply via email to