Update class with list results in multiple add

Mar 8, 2011 at 7:21 PM
Edited Mar 8, 2011 at 7:23 PM

Hi,

I have a class like this one:

public class TestA
{
    public List<TestB> Tmp {get;set;}
}

public class TestB
{
    public List<TestA> Tags {get;set;}
}
In my code, i do the following:
TestA a = .....;

// Here, a.Tmp contains 3 values

// Now, i change the content of a.Tmp
a.Tmp = new List<TestA> { new TestA() };

// Now, i save a
DatabaseService.Current.Database.Save(a);
I thought this code would update the instance of "a" but in fact, all the content of the Tmp property is added as new instance. I mean, if i display the number of item of type type TestA, it will display 2 instead of 1 (the normal one plus the one that i've added to Tmp, which should be added as a relationship, not a new one)... 
Any ideas ? Feel free to contact me if you need more information (it's not easy to explain....)
Thanks !
Mar 8, 2011 at 7:28 PM

You may want to post a full code example.

Coordinator
Mar 8, 2011 at 7:39 PM

Yes, a fuller code example would be helpful because I'm having trouble following you. You a class with a list (which I'm confused how you'll save that class, because it needs some sort of property to use as a unique key).

Then, you created an empty "test a" class. Unless you're using a trigger to set up an identifier for that, how do you expect to get it back? It needs a key.

Also, your code is confusing because you defined TestA as containing a list of TestB. But you just showed creating the List (Tmp) as a list of TestA, which should throw a compiler error.

Can you elaborate further please? Maybe post the full test?

Mar 8, 2011 at 8:30 PM

Ok, let's show me a bit more (real) code :) Here is my Tag class:

public class Tag 
{
    public List<Article> Articles { get; set; }
    public Tag()
    {
        this.Articles = new List<Article>();
    }
}

Now, here is the Article class

public class Article
{
    public List Tags { get; set; }
    public Article()
    {
       this.Tags = new List();
    }
}
As you can see, a Tag can contains a list of Article and an Article can contains a list of Tags :)

Now, i get a list of article from a WCF services (so each articles contains a list of tag) and i assign this list of article to the property Articles of Tag instance and save:

var favorites = from f in DatabaseService.Current.Database.Query<Tag, int>()
                                    select f;
                    if (favorites.Any())
                    {
                        MessageBox.Show(favorites.Count().ToString());
                    }
                    var query = (from t in DatabaseService.Current.Database.Query<Tag, int>()
                                where t.LazyValue.Value.Id == this.m_SelectedTagId
                                select t).FirstOrDefault();
                    if (query != null)
                    {
                        currentTag = query.LazyValue.Value;
                        currentTag.Articles = articles;
                        // Update the current tag
                        DatabaseService.Current.Database.Save(currentTag);
                        DatabaseService.Current.Database.Flush();
                        var favorites2 = from f in DatabaseService.Current.Database.Query<Tag, int>()
                                        select f;
                        if (favorites2.Any())
                        {
                            MessageBox.Show(favorites2.Count().ToString());
                        }
                    }


The first MessageBox.Show display 5, which is correct but why the 2nd MessageBox.Show display 17 ? I thought i will update currentTag but instead, Sterling has added as instance of Tag that he found in the articles...
Thanks !
Coordinator
Mar 9, 2011 at 12:45 PM

What is your unique identifier for the Tag and Article class? What does the key definition look like?

The code snippet is incorrect if you are using "Id" for the key. In the example you gave, you'd be deserializing every item just to find the one with the key. Why not use the "Load" command instead and just pass the id? If it doesn't exist, it will return null.

i.e. var query = DatabaseService.Current.Load<Tag>(this.m_SelectedTagId);

Where are you getting "articles" from in the "currentTag.Articles = articles"?

Mar 9, 2011 at 7:20 PM

Hi Jeremy,

Thanks for your answer (and sorry for the late response). Here are my answers to your questions:

>> What is your unique identifier for the Tag and Article class?

Tag and Article have a property named Id, used for the identifier.

 

>> What does the key definition look like?

Here are the definition:

        protected override List<ITableDefinition> _RegisterTables()
        {
            return new List<ITableDefinition>
            {
                this.CreateTableDefinition<Configuration, Guid>(config => config.Id),
                this.CreateTableDefinition<Tag, int>(tag => tag.Id),
                this.CreateTableDefinition<Article, int>(article => article.Id)
            };
        }

 

>> Where are you getting "articles" from in the "currentTag.Articles = articles"?

"articles" is retrieving by a WCF service: it's a simple new list of articles (new List<Article>()), with some data, that i want to assign to the currentTag field.

 

Thanks !

Coordinator
Mar 9, 2011 at 9:47 PM

I think this is doing exactly what it should. Remember, Sterling is an object-oriented database, not a relational database like SQL. When you ask to save the tag, Sterling will iterate all sub objects. When it finds the articles, it will iterate articles.

Because articles are set up as a "foreign table", sterling will only serialize the id of the article in the tag save. Then, for each article, it will save the individual article just as if you issued a save.

That means if the article has 10 tags, Sterling will save those 10 tags. While Sterling is smart enough not to get stuck in a recursive loop, it will go down as far as it can go.

If you don't want it to save the tags, you either need to clear them before the save, or use the latest changeset which provides an "is dirty" set up. I'll blog about it but basically you can pass a Func<T,bool> that takes an object and returns "true" if it is dirty. If it is not dirty, Sterling won't save it - so you could say for the tags, return false and prevent them from being saved in the nested objects.

Mar 9, 2011 at 9:53 PM

>> so you could say for the tags, return false and prevent them from being saved in the nested objects.

Could it be possible for you to provide me a code sample on how to do that ?

 

Thanks !