Skip to content

autoFetch does't work when cache is true for a model #339

Closed

Description

@mkMoSs
var Reward = db.define('reward', {
        description: { type: 'text'},
        value: { type: 'money'}
    },
    { autoSave: true, autoFetch: true, autoFetchLimit: 3 }
);
var RewardType = db.define('rewardtype', {
        title: { type: 'text', size: 100}
    },
    { autoSave: true }
);

Reward.hasOne('type', RewardType, {reverse: 'rewards' });

In this example Reward has one to many relationships with RewardType when cache is left default (true) Reward.get(...) returns undefined for property "type" while type_id has a value.

When setting cache: false to both models, the 'type' property gets populated as expected using autofetch.

Is this a bug or is it normal behaviour? Spend hours trying to figure why autoFetch wasn't working...

Activity

  1. dresende commented on Sep 16, 2013

    @dresende
    Owner

    cache is something hard to do in this situations, but we still have some work to do on this. What cache means on ORM is Singleton pattern, meaning: when fetching a record that was previously fetched (it uses table+ids to know that), return the same JS object instance.

    This behaviour is seen when you fetch the same record more than one time and keep references to them. They will be the same JS object which means that if you change a property, all references change (because they are one).

    On associations this is still not working properly. The code is somehow "caching" certain records when it doesn't have all data and then when you look for the record (using .find()) it uses the bad cached item. We have to track and solve this.

  2. mkMoSs commented on Sep 16, 2013

    @mkMoSs
    Author

    To give more details on how it happens here's the full code

    db.defineType('money', { datastoreType: function(prop) { return 'decimal(19,2)' }}); //mysql specific
    
    var Achievement = db.define('achievement', {
            title: { type: 'text', size: 100},
            description: { type: 'text'},
            isLocked: { type: 'boolean', defaultValue: false},
            isCompleted: { type: 'boolean', defaultValue: false}
        },
        { autoSave: true, autoFetch: true, autoFetchLimit: 3 } 
    );
    var Reward = db.define('reward', {
            description: { type: 'text'},
            value: { type: 'money'}
        },
        { autoSave: true, autoFetch: true, autoFetchLimit: 3 }
    );
    var RewardType = db.define('rewardtype', {
            title: { type: 'text', size: 100}
        },
        { autoSave: true }
    );
    
    Reward.hasOne('type', RewardType, {reverse: 'rewards' });
    Achievement.hasMany('rewards', Reward);
    
    db.on("connect", function(err) {
        if(err) { console.log("DB connect error:", err); }
        console.log("DB Connected!");
    
        db.drop(function() {
            db.sync(function() {
                RewardType.create([{title: 'xp'}, {title: 'balance'},{title: 'unlock'}], function(){
                    Reward.create({description: '+100', value: 100}, function(){
                        Achievement.create({ title: 'First Steps', description: 'Blah blah'},function(err, ac){
                            Reward.get(1, function(err, reward) {
                                RewardType.get(1, function(err, rewType) {
                                    reward.setType(rewType, function(err){
                                        Reward.get(1, function(err, nw){
                                            console.log(nw);
                                        });
                                    });
                                });
    
                                ac.setRewards([ac]);
                            });
                        });
                    });
                });
            });
    
        });
    });

    As you might notice, I drop everything and recreate them again initially.
    Outputting to console the fetched reward in the end gives:

    DB Connected!
    { description: [Getter/Setter],
      value: [Getter/Setter],
      id: [Getter/Setter],
      type_id: [Getter/Setter],
      type: undefined }
    

    type is undefined which is the problem. After turning off cache in the models:

    DB Connected!
    { description: [Getter/Setter],
      value: [Getter/Setter],
      id: [Getter/Setter],
      type_id: [Getter/Setter],
      type: { title: [Getter/Setter], id: [Getter/Setter] } }
    

    works as expected

  3. mkMoSs commented on Sep 16, 2013

    @mkMoSs
    Author

    I would suggest, until you are able to resolve the problem with caching and associations, to have cache: false by default as opposed being true that it is now.
    It would save people from a lot of confusion (on why autoFetch doesn't work primarily)

  4. dresende commented on Sep 18, 2013

    @dresende
    Owner

    I don't want to change the default behaviour for now. I think I found the problem behind this. I'm fixing this for each association type.

  5. dresende commented on Sep 21, 2013

    @dresende
    Owner

    If it doesn't work (the latest commit), please reopen.

  6. twk-b commented on Sep 22, 2014

    @twk-b

    Seems like this is related to #490. I have this problem in versions 2.1.13 to 2.1.19. I have played around with caching settings, but after reading a variety of tickets I will try looking into that deeper today.

  7. iceNuts commented on Oct 25, 2015

    @iceNuts

    Hi there,

    I am wondering what is the best solution yet, I have the same problem and it has been a year, hope there is some official way to do this.

    Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions