orientechnologies / OrientDB-NET.binary

C#/.NET binary driver for OrientDB
MIT License
93 stars 59 forks source link

Error for database.Insert<Type> for dictionary #54

Closed gohsianghwee closed 9 years ago

gohsianghwee commented 9 years ago

Hi,

I have encountered an error for Dictionary type. Here's the code

[Test] public void GIVEN_EmployeeDictionaryType_class_with_common_data_type__WHENwrite_to_orientdbTHENshould_be_able_to_read() { var employeeClassName = "EmployeeDictionaryType"; var employee = new EmployeeDictionaryType(); employee.Id = Guid.NewGuid(); employee.Name = new Dictionary<string, string>(); employee.Name.Add("Andrew", "Andrew"); employee.Name.Add("Jack", "Jack"); employee.Age = new Dictionary<int, int>(); employee.Age.Add(1, 2); employee.Age.Add(2, 4); employee.BirthDate = new Dictionary<DateTime, DateTime>(); employee.BirthDate.Add(DateTime.Now, DateTime.Now.AddDays(1)); employee.BirthDate.Add(DateTime.Now.AddDays(-3), DateTime.Now.AddDays(-2)); employee.Childs = new Dictionary<int, EmployeeCommonType>(); employee.Childs.Add(1, new EmployeeCommonType() { Id = Guid.NewGuid() }); employee.Childs.Add(2, new EmployeeCommonType() { Id = Guid.NewGuid() }); employee.FavoriteColor = new Dictionary<Color, Color>(); employee.FavoriteColor.Add(Color.Red, Color.Red); employee.FavoriteColor.Add(Color.Blue, Color.Blue); employee.Height = new Dictionary<short, short>(); employee.Height.Add(1, 323); employee.Height.Add(2, 333); employee.Ids = new Dictionary<Guid, Guid>(); employee.Ids.Add(Guid.NewGuid(), Guid.NewGuid()); employee.Ids.Add(Guid.NewGuid(), Guid.NewGuid()); employee.IsMarried = new Dictionary<bool, bool>(); employee.IsMarried.Add(true, true); employee.IsMarried.Add(false, false); employee.Salary = new Dictionary<decimal, decimal>(); employee.Salary.Add((decimal)1, (decimal)1234567890.123456789); employee.Salary.Add((decimal)2, (decimal)1234567890.123456799); employee.Tall = new Dictionary<long, long>(); employee.Tall.Add(1, 3233); employee.Tall.Add(2, 3234); employee.YearlyIncome = new Dictionary<double, double>(); employee.YearlyIncome.Add(2, 3233); employee.YearlyIncome.Add(4, 1234);

        //writer.Insert<EmployeeDictionaryType>(employee, DatabaseName, employeeClassName);

        //dbProvider.CreateConnectionPool(DatabaseName);

        using (var database = new ODatabase(DatabaseName))
        {
            database.Insert(employee)
                    .Into(employeeClassName)
                    .Run();

            var result = database.Query<EmployeeDictionaryType>("SELECT * FROM " + employeeClassName + " WHERE Id = '" + employee.Id + "'").SingleOrDefault();

            Assert.AreEqual(employee.Id, result.Id);
            Assert.AreEqual(employee.Ids.ToList()[0].Key, result.Ids.ToList()[0].Key);
            Assert.AreEqual(employee.Ids.ToList()[1].Key, result.Ids.ToList()[1].Key);
            Assert.AreEqual(employee.Ids.ToList()[0].Value, result.Ids.ToList()[0].Value);
            Assert.AreEqual(employee.Ids.ToList()[1].Value, result.Ids.ToList()[1].Value);
            Assert.AreEqual(employee.Name.ToList()[0].Key, result.Name.ToList()[0].Key);
            Assert.AreEqual(employee.Name.ToList()[1].Key, result.Name.ToList()[1].Key);
            Assert.AreEqual(employee.Name.ToList()[0].Value, result.Name.ToList()[0].Value);
            Assert.AreEqual(employee.Name.ToList()[1].Value, result.Name.ToList()[1].Value);

            Assert.AreEqual(employee.Age.ToList()[0].Key, result.Age.ToList()[0].Key);
            Assert.AreEqual(employee.Age.ToList()[1].Key, result.Age.ToList()[1].Key);
            Assert.AreEqual(employee.Age.ToList()[0].Value, result.Age.ToList()[0].Value);
            Assert.AreEqual(employee.Age.ToList()[1].Value, result.Age.ToList()[1].Value);

            Assert.AreEqual(employee.Salary.ToList()[0].Key, result.Salary.ToList()[0].Key);
            Assert.AreEqual(employee.Salary.ToList()[1].Key, result.Salary.ToList()[1].Key);
            Assert.AreEqual(employee.Salary.ToList()[0].Value, result.Salary.ToList()[0].Value);
            Assert.AreEqual(employee.Salary.ToList()[1].Value, result.Salary.ToList()[1].Value);

            Assert.AreEqual(employee.IsMarried.ToList()[0].Key, result.IsMarried.ToList()[0].Key);
            Assert.AreEqual(employee.IsMarried.ToList()[1].Key, result.IsMarried.ToList()[1].Key);
            Assert.AreEqual(employee.IsMarried.ToList()[0].Value, result.IsMarried.ToList()[0].Value);
            Assert.AreEqual(employee.IsMarried.ToList()[1].Value, result.IsMarried.ToList()[1].Value);

            Assert.AreEqual(employee.Childs[0].Id, result.Childs[0].Id);
            Assert.AreEqual(employee.Childs[1].Id, result.Childs[1].Id);

            Assert.AreEqual(employee.BirthDate.ToList()[0].Key, result.BirthDate.ToList()[0].Key);
            Assert.AreEqual(employee.BirthDate.ToList()[1].Key, result.BirthDate.ToList()[1].Key);
            Assert.AreEqual(employee.BirthDate.ToList()[0].Value, result.BirthDate.ToList()[0].Value);
            Assert.AreEqual(employee.BirthDate.ToList()[1].Value, result.BirthDate.ToList()[1].Value);

            Assert.AreEqual(employee.YearlyIncome.ToList()[0].Key, result.YearlyIncome.ToList()[0].Key);
            Assert.AreEqual(employee.YearlyIncome.ToList()[1].Key, result.YearlyIncome.ToList()[1].Key);
            Assert.AreEqual(employee.YearlyIncome.ToList()[0].Value, result.YearlyIncome.ToList()[0].Value);
            Assert.AreEqual(employee.YearlyIncome.ToList()[1].Value, result.YearlyIncome.ToList()[1].Value);

            Assert.AreEqual(employee.FavoriteColor.ToList()[0].Key, result.FavoriteColor.ToList()[0].Key);
            Assert.AreEqual(employee.FavoriteColor.ToList()[1].Key, result.FavoriteColor.ToList()[1].Key);
            Assert.AreEqual(employee.FavoriteColor.ToList()[0].Value, result.FavoriteColor.ToList()[0].Value);
            Assert.AreEqual(employee.FavoriteColor.ToList()[1].Value, result.FavoriteColor.ToList()[1].Value);

            Assert.AreEqual(employee.Height.ToList()[0].Key, result.Height.ToList()[0].Key);
            Assert.AreEqual(employee.Height.ToList()[1].Key, result.Height.ToList()[1].Key);
            Assert.AreEqual(employee.Height.ToList()[0].Value, result.Height.ToList()[0].Value);
            Assert.AreEqual(employee.Height.ToList()[1].Value, result.Height.ToList()[1].Value);

            Assert.AreEqual(employee.Tall.ToList()[0].Key, result.Tall.ToList()[0].Key);
            Assert.AreEqual(employee.Tall.ToList()[1].Key, result.Tall.ToList()[1].Key);
            Assert.AreEqual(employee.Tall.ToList()[0].Value, result.Tall.ToList()[0].Value);
            Assert.AreEqual(employee.Tall.ToList()[1].Value, result.Tall.ToList()[1].Value);
            database.Command("DELETE FROM " + DemoEmployeeClassName + " WHERE Id = '" + employee.Id + "'");
        }
    }

public class EmployeeDictionaryType { public Guid Id { get; set; }

    public Dictionary<Guid, Guid> Ids { get; set; }
    public Dictionary<string, string> Name { get; set; }

    public Dictionary<int, int> Age { get; set; }

    public Dictionary<decimal, decimal> Salary { get; set; }

    public Dictionary<bool, bool> IsMarried { get; set; }

    public Dictionary<DateTime, DateTime> BirthDate { get; set; }

    public Dictionary<double, double> YearlyIncome { get; set; }

    public Dictionary<short, short> Height { get; set; }

    public Dictionary<long, long> Tall { get; set; }

    public Dictionary<Color, Color> FavoriteColor { get; set; }

    public Dictionary<int, EmployeeCommonType> Childs { get; set; }
}

public class EmployeeCommonType { public Guid Id { get; set; }

    public string Name { get; set; }

    public int Age { get; set; }

    public decimal Salary { get; set; }

    public bool IsMarried { get; set; }

    public DateTime BirthDate { get; set; }

    public double YearlyIncome { get; set; }

    public short Height { get; set; }

    public long Tall { get; set; }

    public Color FavoriteColor { get; set; }
}
GoorMoon commented 9 years ago

@gohsianghwee, I looked in this issue and don't understand what do you want to see in the database side ? You have properties that have variants of Dictionary<?,?> that fields may be exposed as EmbedeMap in the OrientDB but them must be of type Dictionary<string,ORecord>. Could you explain more about what you expect from this ?

gohsianghwee commented 9 years ago

Hi @GoorMoon,

Actually my colleague has some numerous issues with the driver especially insert and field mapping. I have reported those issues before and to make my life simple I therefore created a unit test to test all type supported by Dictionary and Sorted list to ensure the Dictionary cover all the cases. Basically we will use Dictionary<int, string>, Dictionary<guid, class>, Dictionary<string,string> and Dictionary<enum, class>,

Please let me know if you need more info

GoorMoon commented 9 years ago

@gohsianghwee,

You Dictionary property must have string value as key and object as value take look at following test-case GitHub_issue23 property MyKeyValues

That create following record in the orientdb

@rid @class @version SomeOtherId Name Age SomeVeryLongNumber BirthDate Salary Commission MyFavoriteColor IsMarried SomeIntegerList SomeIntegerArrayList SomeDecimalList SomeDecomeArray Kids SomeIListInteger MyKeyValues Allowance
#11:0 DemoEmployee 1 ad2c470e-ce72-4597-aed7-cc1f2a7be613 Janet 33 12345678901234568 2015-01-24 02:02:02 23434.1234567891 23434.1234567891 Yellow true [1,2,3] [4,2,3] [23434.1234567891] [23434.123456789,23434.123456789,23434.123456789] [{"SomeIntegerArrayList":[4,2,3],"Age":33,"SomeDecimalList":[23434.1234567891],"SomeIntegerList":[1,2,3],"SomeVeryLongNumber":12345678901234568,"@class":"DemoChild","IsMarried":true,"BirthDate":"2015-01-24 02:02:02","Name":"Janet","Commission":23434.1234567891,"Allowance":3434.1235,"Salary":23434.1234567891,"SomeDecomeArray":[23434.123456789,23434.123456789,23434.123456789]}] [7] {"1":"Name","2":123445555555555} 3434.1235

If this make sense ?

gohsianghwee commented 9 years ago

Hi @GoorMoon ,

May I confirm with you again, the string is the only key allowed for Dictionary and SortedList, not integer, enum or others?

Cordially, Goh

GoorMoon commented 9 years ago

Yes, I can try to convert keys to the string but this be unpredictable behavior in case of DateTime for Example.

gohsianghwee commented 9 years ago

Hi @GoorMoon ,

I don't need DateTime as key actually, that's for Unit Testing. I appreciate if you can convert as string for integer and enum. That will be more than enough

gohsianghwee commented 9 years ago

Hi @GoorMoon ,

Thanks for your update. I think it doesn't work for GUID and short and long type. I want to fix it but I am not sure why my github version differ from yours and comparison show no difference. I have added a method at DictionaryFieldMapping.cs and it solved.

protected override void AddItemToCollection(object collection, int index, object item) { var enumerator = ((IDictionary)item).GetEnumerator(); while (enumerator.MoveNext()) { object key = enumerator.Key; object value = enumerator.Value;

            if (_keyType == typeof(Int32) || _keyType == typeof(Int64) || _keyType == typeof(Int16))
            {
                key = Convert.ChangeType(enumerator.Key, _keyType);
            }
            else if (_keyType.IsEnum)
            {
                key = Enum.Parse(_keyType, enumerator.Key.ToString());
            }
            else if (_keyType == typeof(Guid))
            {
                key = Guid.Parse(enumerator.Key.ToString());
            }
            if (_valueType == typeof(Int32) || _keyType == typeof(Int64) || _keyType == typeof(Int16))
            {
                value = Convert.ChangeType(enumerator.Value, _valueType);
            }
            else if (_valueType.IsEnum)
            {
                value = Enum.Parse(_valueType, enumerator.Value.ToString());
            }
            else if (_valueType == typeof(Guid))
            {
                value = Guid.Parse(enumerator.Value.ToString());
            }
            if (_needsMapping)
            {
                var oMaped = _elementFactory();
                _mapper.ToObject((ODocument)value, oMaped);
                value = oMaped;
            }

            ((IDictionary)collection).Add(key, value);
        }
    }