NOODB: Arrays Work – Mostly

March 27, 2010

Arrays mostly worked due to the collection support. But, not quite. While arrays are IList objects, they are of fixed size. Calling ADD on an array is invalid. Boom! As part of my anti-boom campaign, I figured I should fix this.

I had to code specifically for the array. If it’s an array, then it initializes the array to the correct size at instantiation. As it loops through the items, it populates the specific element and increments an index.

The arrays work as long as they’re a property of an object. It also works if you save an array of a particular type. But, saving an array of mixed types, by itself, does not work. The work on Collections and Arrays have revealed a design flaw with the database. Correcting this design flaw will probably be a significant task, but necessary. It will allow me to simplify the save operations. In essence, it needs to treat everything as an object rather than as object and properties. Most of the work (possibly all) is the database and database code.

I’m not sure when I’m going to tackle that. I’ll have to decide if I want to keep adding features or address this now. Adding new features won’t increase the complexity, so it’ll just come down to what I feel like doing. But, if I know me, I’ll probably start it tomorrow.

Enough about that. Here are the working array tests. All of the samples to date have shown the save and verification process. I’m going to reduce that to just the code that does the save. Trust that I have the asserts to confirm that it comes out the same way it went in. If you feel that more code would be helpful, let me know.

Working Tests

                int[] x = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
                client.Save(x);

                ArrayTester array = new ArrayTester
                {
                    FavoriteNumber = 93,
                    Items = new ArrayItem[] 
                     { 
                         new ArrayItem {ItemName = "1"},
                         new ArrayItem {ItemName = "2"}
                     }
                };

                ThisWillBeAPain[] pains = new ThisWillBeAPain[]
                {
                    new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = false, Ouchy = "1"},
                    new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = true, Ouchy = "2"},
                    new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = false, Ouchy = "3"},
                    new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = false, Ouchy = "3"}
                };

Broken Test


                object[] objects = new object[] { 3, false, "swell", new ArrayItem { ItemName = "item" } };
                client.Save(objects);

                object[] fromDb = client.GetObjects<object[]>()[0];
                Assert.AreEqual(4, fromDb.Length);
                Assert.AreEqual(3, fromDb[0]);
                Assert.AreEqual(false, fromDb[1]);
                Assert.AreEqual("swell", fromDb[2]);
                Assert.IsInstanceOfType(fromDb[3], typeof(ArrayItem));

The first assert works, but that’s it. The values all come back as null because values are stored at the property level, and there aren’t any properties.


NOODB: Collections Finally Work

March 26, 2010

Collections were really tedious. I’m going to have to go back and do some refactoring.

These test demonstrate 3 things:

  1. Saving a collection directly
  2. Saving a collection as a property of another object
  3. Saving a custom collection directly (ie:   MyStuffCollection:Collection<MyStuff> )

Save Directly

                Collection<ThisWillBeAPain> pain = new Collection<ThisWillBeAPain>
                {
                    new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = false, Ouchy = "1"},
                    new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = true, Ouchy = "2"},
                    new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = false, Ouchy = "3"}
                };
                client.Save(pain);
                Assert.AreEqual(3, client.GetObjects<Collection<ThisWillBeAPain>>()[0].Count);

Save as a property of another object

                OhMy my = new OhMy
                {
                    Id = Guid.NewGuid(),
                    Pains = new Collection<ThisWillBeAPain>
                    {
                        new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = true, Ouchy = "Make it stop 1"},
                        new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = false, Ouchy = "Make it stop 2"},
                        new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = true, Ouchy = "Make it stop 3"},
                    }
                };

                client.Save(my);

                OhMy fromDb = client.GetObjects<OhMy>()[0];
                Assert.AreEqual(3, fromDb.Pains.Count);

Save a custom collection directly.

                ThisWillBeAPainCollection pain = new ThisWillBeAPainCollection
                {
                    new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = false, Ouchy = "1"},
                    new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = true, Ouchy = "2"},
                    new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = false, Ouchy = "3"},
                    new ThisWillBeAPain {Id = Guid.NewGuid(), ItHurts = false, Ouchy = "3"}
                };
                pain.FavoriteNumber = 87;
                client.Save(pain);


An array is an IList, so I’m hoping it automatically works… we’ll soon see.


NOODB: Generics and Collections

March 22, 2010

Progress has been slow due to a busy schedule over the last couple weeks.

This week I worked on the type management system a little bit. I was converting the type name to thought I was a more manageable and code friendly syntax, but that didn’t work out, so reverted back to just the .Net type name. I parse it as needed, which isn’t as often as I thought it would be.

Generic support and Collection support is a joint effort. The serializer for collections is working. I had second thoughts about how I was doing it and revisited; it held up, so no changes.

Now I’m working on saving them to the database. The type-agnostic objects that represent the graph on the server are being properly populated; now it’s just a matter of actually saving it, then restoring it. This part of it is pretty tedious. My head wasn’t in the right place when I worked on it last night, so I ended up eliminating all of the StyleCop violations instead, just to accomplish something.


Collection Serializer Working

March 17, 2010

I might have to revisit this for more advanced scenarios, but it’s working for basic purposes. Currently, it requires a collection property to be read/write, but I’ll work on that. The serializer only serializes read/write properties. It’ll have to be smarter about collections and append to the collection if it already exists, which is normally how collection properties work. Also, it’s not going to work for arrays, so that’ll have to be handled separately.

I’ve been saying “collection”, but it’s actually “IList”. That’s the highest interface with the add method. List implements it. Collection implements it. Sounds good to me.

BlahCollection is Collection<Blah>. BlahCollection has 2 additional properties: a property of another BlahCollection, and an integer property. Those are to make sure it does the whole graph, and that other properties are handled too.

        [TestMethod]
        public void ShouldSerializeAndDeserializeCollection()
        {
            BlahCollection collection = new BlahCollection
            {               
                new Blah { FirstName = "first 1", LastName = "last 1" },
                new Blah { FirstName = "first 2", LastName = "last 2" }
            };
            collection.MyFavoriteNumber = 57;

            collection.NestedWithSetter = new BlahCollection
            {
                new Blah {FirstName = "nested first 1", LastName = "nested last 1"},
                new Blah {FirstName = "nested first 2", LastName = "nested last 2"},
                
            };
            collection.NestedWithSetter.MyFavoriteNumber = 1003;

            string serialized = new Serializer().Serialize(collection);
            BlahCollection deserialized = (BlahCollection)new Serializer().Deserialize(serialized);

            // root collection
            Assert.AreEqual(2, deserialized.Count);
            Assert.AreEqual("first 1", deserialized[0].FirstName);
            Assert.AreEqual("last 1", deserialized[0].LastName);
            Assert.AreEqual("first 2", deserialized[1].FirstName);
            Assert.AreEqual("last 2", deserialized[1].LastName);
            Assert.AreEqual(57, deserialized.MyFavoriteNumber);

            // nested with setter
            Assert.AreEqual(2, deserialized.NestedWithSetter.Count);
            Assert.AreEqual("nested first 1", deserialized.NestedWithSetter[0].FirstName);
            Assert.AreEqual("nested last 1", deserialized.NestedWithSetter[0].LastName);
            Assert.AreEqual("nested first 2", deserialized.NestedWithSetter[1].FirstName);
            Assert.AreEqual("nested last 2", deserialized.NestedWithSetter[1].LastName);
            Assert.AreEqual(1003, deserialized.NestedWithSetter.MyFavoriteNumber);
        }


NOODB: Nullable Types Work

March 11, 2010

The SAVE part of NullableTypes went in with almost no work.

The retrieve, though… that got hairy. It required serializer changes and server changes.

The CRAZY object has a a few nullable type properites. The first test sets them all to null and shows that they come bgck as null. The second test gives them each a value and confirms that the value comes back.

 

        [TestMethod]
        public void TestNull()
        {
            TestUtility.DeleteTestData();
            try
            {
                NoodbClient client = new NoodbClient(new Server(TestUtility.DefaultUnityContainer));
                client.RegisterType<Crazy>();

                Crazy crazy = new Crazy
                {
                    Id = Guid.NewGuid(),
                    NullableBool = null,
                    NullableDate = null,
                    NullableInt = null,
                    NullableGuid = null
                };

                client.Save(crazy);

                Crazy fromDb = client.GetObjects<Crazy>()[0];
                Assert.IsNull(fromDb.NullableBool);
                Assert.IsNull(fromDb.NullableDate);
                Assert.IsNull(fromDb.NullableInt);
                Assert.IsNull(fromDb.NullableGuid);
            }
            finally
            {
                // TestUtility.DeleteTestData();
            }
        }

        [TestMethod]
        public void TestNotNull()
        {
            TestUtility.DeleteTestData();
            try
            {
                NoodbClient client = new NoodbClient(new Server(TestUtility.DefaultUnityContainer));
                client.RegisterType<Crazy>();

                Crazy crazy = new Crazy
                {
                    Id = Guid.NewGuid(),
                    NullableBool = true,
                    NullableDate = DateTime.Parse("1/3/2010"),
                    NullableInt = 79,
                    NullableGuid = Guid.NewGuid()
                };

                client.Save(crazy);

                Crazy fromDb = client.GetObjects<Crazy>()[0];
                Assert.IsTrue(fromDb.NullableBool.Value);
                Assert.AreEqual(DateTime.Parse("1/3/2010"), fromDb.NullableDate);
                Assert.AreEqual(79, fromDb.NullableInt);
                Assert.IsNotNull(fromDb.NullableGuid);
            }
            finally
            {
                // TestUtility.DeleteTestData();
            }
        }

Nullable enums don’t work yet. I added that to the TO DO list.


NOODB: Abstract Classes

March 10, 2010

This is very similar to the INTERFACE update.

The CAR object has a property called DRIVER, which is of type DRIVER, which is an abstract class.

GIRAFFE inherits from DRIVER

BABY GIRAFFE inherits from GIRAFFE.

CHRYSLER300 inherits from CAR.

So, the type of DRIVER is a base class. We assign to it an instance of BABYGIRAFFE which is, ultimately, a driver.

                NoodbClient client = new NoodbClient(new Server(TestUtility.DefaultUnityContainer));
                client.RegisterType<Chrysler300>();
                client.RegisterType<BabyGiraffe>();

                Car car = new Chrysler300
                {
                    Driver = new BabyGiraffe { NeckLength = 40, Id=Guid.NewGuid() },
                    Id = Guid.NewGuid()
                };

                client.Save(car);

                Car fromDb = client.GetObjects<Car>()[0];
                Assert.IsInstanceOfType(fromDb.Driver, typeof(BabyGiraffe));

This went in pretty easy. The PropertyResolver had a problem with BabyGiraffe because, as it worked up the graph, it found the same properties multiple times. So, it would try to add the same property to the dictionary multiple times. The knee-jerk reaction was to add a CONTAINS check before the add, but I didn’t want to do that until tracing the whole thing and confirming the problem.

                    // C : B : A
                    // When c and b are parsed, they will both try to add the properties from A.
                    // So it will encounter the same properties multiple times.
                    if (!objectProperties.Contains(p.ObjectTypePropertyId))
                    {
                        objectProperties.Add(p);
                    }

I have a couple more scenarios to test, but I expect them to work. (IE: the property type is somewhere in the middle of a class hierarchy)


NOODB: Properties as Interfaces

March 8, 2010

To date, all of the examples have been with concrete classes. A MOVIE REVIEW has a MOVIE object and an AUTHOR object.

But, what if the property types are interfaces, not concrete classes?

In this example: MovieReview3 implements IMovieReview3. There are two object properties: IAuthor3 and IMovie3.

On the wiki todo list, I speculated that this would work without any changes. Obviously I didn’t think about it, because it didn’t work. I had to make 2 key changes.

Multiple Properties

The TypeRegistration builder was ignoring interfaces with a comment that it would have to be revisited. Tonight, I had to revisit. The problem is that the builder parses the type being registered and all its related types. If the properties are defined in the interface and the implementation, then it picks up the properties twice: one set from the implementation and one set from the interface. The quick work-around was to not parse the interfaces.

I changed it to not ignore interfaces. Now, it ignores properties in a class that are defined in either a base class or an interface. (the base class part isn’t tested yet). So, MOVIE and AUTHOR are associated to IMovieReview3, not MovieReview3. Now, there’s only one copy.

Xml Building

The server extracts the db from the database and builds an xml document that the deserializer expects. The construction of that xml was based on the object type metadata. The metadata says that the properties are interfaces, to it would come through as TYPE=IAUTHOR3. The deserializer would say “okey-doke”, and try to instantiate an instance of IAUTHOR3. Here’s the thing… you can instantiate an interface due to that pesky “it just doesn’t make sense” logic. You can only instantiate concrete classes.

To correct this, I:

  1. updated the DataProperty object. Added a ReferencedObjectTypeId property.
  2. updated the SqlObjectDataContext to update the new property.
  3. Changed the server to use ReferenecedObjectTypeId rather than the id from the meta data (which represents the interface).

The DataProperty object is now a 3 property bag. The Object Data Context populates this object with just the 3 pieces of information that NOODB needs to put everything together.

The Test

                IMovieReview3 review = new MovieReview3
                {
                    Author = new Author3a { Name = "Jay", Title = "hack" },
                    Comments = "swell",
                    Id = Guid.NewGuid(),
                    Movie = new Movie3 { Director = "director", Rating = "rating", Title = "title", Id = Guid.NewGuid() }
                };
                client.Save(review);

                IMovieReview3 fromDb = client.GetObjects<MovieReview3>()[0];
                Assert.IsInstanceOfType(fromDb.Movie, typeof(Movie3));
                Assert.IsInstanceOfType(fromDb.Author, typeof(Author3a));
                Assert.AreEqual("Jay", fromDb.Author.Name);
                Assert.AreEqual("hack", fromDb.Author.Title);
                Assert.AreEqual("director", fromDb.Movie.Director);

Author is an IAuthor3.

Movie is an IMovie3.

The test shows that the types that come out are the same types that went in, even though the property has no knowledge of the concrete class type.

I have to test the same functionality with abstract classes. After tonight’s changes, i think it will work, but I’ve said that before. Guess I’ll have to test it.