Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows phone 8 MVVM Linq table Creates new instance on NotifyPropertyChanging

I have a Linq DataContext as a database for the application. I have set up the MVVM pattern and am able to insert new records into the database. However when I load these records and try update them a new instance of the record is being created in the background and being updated with the property changes. So when they UI is invoking the save command the originally loaded instance of the record has no changes and is not saved.

from what I can tell this is the sequence of events

  • Load Instance 1
  • Start updating property
  • NotifyPropertyChanging is called
  • New instance2 is loaded
  • New Instance2 is updated
  • Invoke save changes from UI for Instance 1
  • No changes are made because Instance 1 has not been updated

Below is the code I have:

/* This is the Entity */

[Table]
public class User : IDisposable, INotifyPropertyChanged, INotifyPropertyChanging
{
    private MyDataContext context;

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (null != handler)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangingEventHandler PropertyChanging;
    private void NotifyPropertyChanging(String propertyName)
    {
        PropertyChangingEventHandler handler = PropertyChanging;
        if (null != handler)
        {
            handler(this, new PropertyChangingEventArgs(propertyName));
        }
    }

    public void Dispose()
    {
        context.Dispose();
    }

    private Guid _id;
    [Column(IsPrimaryKey = true, IsDbGenerated = false, DbType = "UNIQUEIDENTIFIER NOT NULL", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
    public Guid Id
    {
        get { return _id; }
        set
        {
            if (_id != value)
            {
                NotifyPropertyChanging("Id");
                _id = value;
                NotifyPropertyChanged("Id");
            }
        }
    }

    private string _name;
    [Column(CanBeNull = false)]
    public string Name
    {
        get { return _name; }
        set
        {
            if (_name != value)
            {
                NotifyPropertyChanging("Name"); // This line creates the new entity
                _name = value;
                NotifyPropertyChanged("Name");
            }
        }
    }

    public User()
    {
        this.context = MyDataContext.GetContext();
    }

    public override void SaveChanges()
    {
        if (_id == Guid.Empty)
        {
            this.Id = Guid.NewGuid();
            context.Users.InsertOnSubmit(this);
            context.SubmitChanges();
        }
        else
        {
            context.SubmitChanges();
        }
    }

    public static User NewInstance()
    {
        return new User
        {
            Name = String.Empty
        };
    }
}

/* This is the data context */

public class MyDataContext : DataContext
{
    // Specify the connection string as a static, used in main page and app.xaml.
    public static string ConnectionString = "Data Source=isostore:/MyApp.sdf;Password=pwd";

    public MyDataContext(string connectionString) : base(connectionString) { }

    public static MyDataContext GetContext()
    {
        var context = new MyDataContext(ConnectionString);
        return context;
    }

    public Table<User> Users;
}

/* This is the View Model */

public sealed class UserViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private User _user;

    public UserViewModel(Guid id)
    {
        using (MyDataContext context = new MyDataContext(MyDataContext.ConnectionString))
        {
            _User = context.User.First(u => u.Id == id);
        }
    }

    public UserViewModel(User user)
    {
        _user = user;
    }

    public UserViewModel()
    {
        _user = User.NewInstance();
    }

    public string Name
    {
        get { return _user.Name; }
        set
        {
            _user.Name = value;
            NotifyPropertyChanged("Name");
        }
    }

    private ICommand _saveCommand;
    public ICommand SaveCommand
    {
        get
        {
            return _saveCommand ?? (_saveCommand = new GenericCommand(() =>
            {
                _user.SaveChanges();
            }, true));
        }
    }
}
like image 232
Koenyn Avatar asked Mar 12 '14 06:03

Koenyn


1 Answers

In your MyDataContext I would think you want the below instead, a basic singleton concept so that you're working on the same object and thus saving the same object with changes.

private static DataContext context = null;

public static MyDataContext GetContext()
{
    if(context == null)
        context = new MyDataContext(ConnectionString);
    return context;
}

edit- Note, this can have a major impact on your application in the big picture. May need to redesign when a new one is created, and if/when you should specifically set it to null.

like image 190
bland Avatar answered Nov 13 '22 21:11

bland