Adam Benoit

Windows Phone Development

Entity Framework & Windows Phone: Part 3

Posted on

by Adam

Entity Framework & Windows Phone: Part 1 | Part 2 | Part 3

In the first two parts we used Entity Framework to create a model to keep track of ideas for other app, generated a .sdf database file, generated data classes then fixed errors in the class so it will work in Windows Phone. In this part we will add some structure to our app, setup the db on first run and populate some default data into some tables. Then finally we will create a couple of views to display the info in the database.

Based on feedback, I would like to clarify that at this point we are done using Entity framework and are using LINQ to SQL to manage the database that we used EF to design in Part 1.

You can grab the source code here.

Part 3: Consuming Data Classes in Windows Phone Application

Now that we have our generated classes in our project, it is time to use them. We do need to do a bit of setup first. In Part 2, we created a folder called Models. This is part of a design pattern that is recommended for all but the most trivial WP7 applications. We will be utilizing this pattern in our application.

  1. The first thing we will do is to add a folder to the AppTracker.WP project called Views.
  2. Now we are going to create a class to handle population of default data in the database. Add a folder called DefaultData to the AppTracker.WP project. In it, add a class called DefaultData.csIn this class we include functions to:
    • Check if the db exists and deletes it if need be. I use this to help facilitate the initial creation and  re-creation of the db. Useful if you want to add a reset option.
      public bool CreateDatabase(bool deleteExisting = false)
      {
          try
          {
              if (_context.DatabaseExists())
              {
                  if(deleteExisting)
                  {
                      _context.DeleteDatabase();
                  }
                  else
                  {
                      return false;
                  }
              }   
              _context.CreateDatabase();
              return true;
          }
          catch (Exception ex)
          {
              if (System.Diagnostics.Debugger.IsAttached)
              {
                  MessageBox.Show(ex.Message);
              }
              return false;
          }
      }
    • Populate 5 tables with default data:
      public bool PopulateStatusTable()
      {
          try
          {
              var statuses = new List<Status>();
      
              var status = new Status { Id = 1, Name = "In Progress", Description = "Description Description Description Description Description" };
              statuses.Add(status);
      
              status = new Status { Id = 2, Name = "Games", Description = "Description Description Description Description Description" };
              statuses.Add(status);
      
              status = new Status { Id = 3, Name = "Other", Description = "Description Description Description Description Description" };
              statuses.Add(status);
      
              _context.Status.InsertAllOnSubmit(statuses);
              _context.SubmitChanges();
      
              return true;
          }
          catch (Exception ex)
          {
              if (System.Diagnostics.Debugger.IsAttached)
              {
                  MessageBox.Show(ex.Message);
              }
              return false;
          }
      }
      
      public bool PopulatePlatformsTable()
      {
          try
          {
              var platforms = new List<Platform>();
      
              var platform = new Platform { Id = 1, Name = "Windows Phone", Description = "Description Description Description Description Description" };
              platforms.Add(platform);
      
              platform = new Platform { Id = 2, Name = "Android", Description = "Description Description Description Description Description" };
              platforms.Add(platform);
      
              platform = new Platform { Id = 3, Name = "iOS", Description = "Description Description Description Description Description" };
              platforms.Add(platform);
      
              _context.Platforms.InsertAllOnSubmit(platforms);
              _context.SubmitChanges();
      
              return true;
          }
          catch (Exception ex)
          {
              if (System.Diagnostics.Debugger.IsAttached)
              {
                  MessageBox.Show(ex.Message);
              }
              return false;
          }
      }
      
      public bool PopulateTagsTable()
      {
          try
          {
              var tags = new List<Tag>();
      
              var category = new Tag { Id = 1, Name = "Tag 1", Description = "Description Description Description Description Description" };
              tags.Add(category);
      
              category = new Tag { Id = 2, Name = "Tag 2", Description = "Description Description Description Description Description" };
              tags.Add(category);
      
              category = new Tag { Id = 3, Name = "Tag 3", Description = "Description Description Description Description Description" };
              tags.Add(category);
      
              _context.Tags.InsertAllOnSubmit(tags);
              _context.SubmitChanges();
      
              return true;
          }
          catch (Exception ex)
          {
              if (System.Diagnostics.Debugger.IsAttached)
              {
                  MessageBox.Show(ex.Message);
              }
              return false;
          }
      }
      public bool PopulateIdeasTable()
      {
          try
          {
              var ideas = new List<Idea>();
      
              var idea = new Idea { Id = 1, Name = "Idea 1", Description = "Description Description Description Description Description", CategoryId = 1, StatusId = 1, DateAdded = DateTime.Now, DateUpdated = DateTime.Now };
              ideas.Add(idea);
      
              idea = new Idea { Id = 2, Name = "Idea 2", Description = "Description Description Description Description Description", CategoryId = 1, StatusId = 1, DateAdded = DateTime.Now, DateUpdated = DateTime.Now };
              ideas.Add(idea);
      
              idea = new Idea { Id = 3, Name = "Idea 3", Description = "Description Description Description Description Description", CategoryId = 1, StatusId = 1, DateAdded = DateTime.Now, DateUpdated = DateTime.Now};
              ideas.Add(idea);
      
              _context.Ideas.InsertAllOnSubmit(ideas);
              _context.SubmitChanges();
      
              return true;
          }
          catch (Exception ex)
          {
              if (System.Diagnostics.Debugger.IsAttached)
              {
                  MessageBox.Show(ex.Message);
              }
              return false;
          }
      }
  3. Now that we have a way to populate the tables, lets make that happen. While there are several places to do this, I prefer in the constructor of the MainViewModel.cs file. This makes sure the db is filled when the app is started.
    private const string ConnectionString = @"isostore:/AppTrackerDatabase.sdf";
    private AppTrackerDataContext _context = new AppTrackerDataContext(ConnectionString);
    
    public MainViewModel()
    {
        try
        {
            if (!_context.DatabaseExists())
            {
                // create database if it does not exist
                var dd = new DefaultData.DefaultData(_context);
                if (dd.CreateDatabase(true))
                {
                    if (Debugger.IsAttached)
                    {
                        MessageBox.Show("Database created.");
                    }
                }
                else
                {
                    if (Debugger.IsAttached)
                    {
                        MessageBox.Show("Error creating database");
                    }
                }
                if (dd.PopulateCategoriesTable() && dd.PopulatePlatformsTable() && dd.PopulateStatusTable() && dd.PopulateTagsTable() && dd.PopulateIdeasTable()))
                {
                    if (Debugger.IsAttached)
                    {
                        MessageBox.Show("Tables populated");
                    }
                }
                else
                {
                    if (Debugger.IsAttached)
                    {
                        MessageBox.Show("Error populating tables.");
                    }
                }
            }
            else
            {
                if (Debugger.IsAttached)
                {
                    MessageBox.Show("Database Exists.");
                }
            }
        }
        catch (Exception ex )
        {
            if (Debugger.IsAttached)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
  4. Now we make sure the Items property in the MainViewModel triggers the PropertyChanged event so the UI updates.
    private ObservableCollection _ideas; 
    public ObservableCollection Ideas
    {
        get
        {
            return _ideas;
        }
        set
        {
            if (value != _ideas)
            {
                _ideas = value;
                NotifyPropertyChanged("Ideas");
            }
        }
    }
  5. Then we update the LoadData function to pull all Idea records load them into the Items ObservableCollection. This loading triggers the PropertyChanged event and causes the UI to update.
    public void LoadData()
    {
        var ideas = _context.Ideas.Where(i => i.Id != 0);
        Ideas = new ObservableCollection(ideas.ToList());
        this.IsDataLoaded = true;
    }
  6. Next we update the MainPage.xaml file to include the CategoryId and StatusId info. I wont be covering data binding in this post but will in the near future.
    <ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding Ideas}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Margin="0,0,0,17" Width="432" Height="200">
                    <TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                    <TextBlock Text="{Binding Description}" TextWrapping="Wrap" Margin="12,-6,12,5" Style="{StaticResource PhoneTextSubtleStyle}"/>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="CategoryId: " TextWrapping="Wrap" Margin="12,-6,12,5" Style="{StaticResource PhoneTextSubtleStyle}" Width="122" />
                        <TextBlock Text="{Binding CategoryId}" TextWrapping="Wrap" Margin="12,-6,12,5" Style="{StaticResource PhoneTextSubtleStyle}" Width="193" />
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="StatusId: " TextWrapping="Wrap" Margin="12,-6,12,5" Style="{StaticResource PhoneTextSubtleStyle}" Width="122" />
                        <TextBlock Text="{Binding StatusId}" TextWrapping="Wrap" Margin="12,-6,12,5" Style="{StaticResource PhoneTextSubtleStyle}"/>
                    </StackPanel>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

Now if we run the project, we will see a page with the 3 Ideas displayed.

At this point, we have a starting point to an application with a database created from an entity model. If we need to update the entity model in the future, we can follow the steps in the second part and simply update the DataClasses.cs file. Building the solution will then show you any breaking changes and help hunt down where you need to update.

There is still plenty of work to do to make this a marketplace worthy app but we will over the next few months cover these parts until we have something we will actually submit.

 

About Adam

Adam Benoit is a Quality Assurance Analyst, Contributing Author and Windows Phone Developer. View all posts by Adam →
This entry was posted in Development, Featured, Howto. Bookmark the permalink.

7 Responses to Entity Framework & Windows Phone: Part 3

  1. Pingback: Entity Framework & Windows Phone: Part 2 | Adam Benoit

  2. Your implementation is using LINQ to SQL not Entity Framework. You only used EF to manage the database schema. All of your client code is (the WP7 subset of) LINQ to SQL.

    • Adam

      Hi Jim,

      Thanks for your comment.

      Yes, you are correct. EF is only used to create the Db.

      I did once upon a time try to make EF work directly with WP but too many errors were unfixable with the EF generated classes.

      If you have any insights into how to make EF work directly with WP, please let me know. I would love to find out how. :)

      Adam

  3. Pingback: Entity Framework & Windows Phone: Part 3 | azkafaiz.com

  4. Use my SQL Server Compact toolbox to create enhanced LINQ to SQL classes, and avoid many of your manual steps – http://sqlcetoolbox.codeplex.com + http://wp.qmatteoq.com/how-to-get-write-access-to-a-prepopulated-sql-ce-database-in-a-windows-phone-application/

    • Adam

      Does it allow me to use an existing SDF file to generate the classes? I like using EF to create the data model and SDF file but I really don’t like the command line step.
      Also, do the generated classes have something similar to the CreateDatabase and DatabaseExists methods generated by SqlMetal?

      Cheers,
      Adam

  5. Pingback: Entity Framework & Windows Phone: Part 3