IT tutorials
 
Technology
 

Windows Phone 8 : Databases and Storage (part 5) - Local Databases - Associations

8/15/2013 11:29:03 AM
- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019

3.3 Associations

The data types for each property in the table classes you have seen have been simple types. The types have been simple because they need to be stored in the local database. To be stored in the local database, they need to be convertible to database types (for example, strings are stored as NVARCHARs). Even though you’re going to be dealing with classes, you will still have to remember that it is a relational database underneath the covers. So when you need more structure, you will need associated tables (or associations).

For instance, let’s assume we have a second table class that holds information about the publisher of a game:

[Table]
public class Publisher :
  INotifyPropertyChanging, INotifyPropertyChanged
{
  int _id;

  [Column(IsPrimaryKey = true, IsDbGenerated = true)]
  public int Id
  {
    get { return _id; }
    set
    {
      RaisePropertyChanging("Id");
      _id= value;
      RaisePropertyChanged("Id");
    }
  }

  string _name;

  [Column]
  public string Name
  {
    get { return _name; }
    set
    {
      RaisePropertyChanging("Name");
      _name = value;
      RaisePropertyChanged("Name");
    }
  }

  string _website;

  [Column]
  public string Website
  {
    get { return _website; }
    set
    {
      RaisePropertyChanging("Website");
      _website = value;
      RaisePropertyChanged("Website");
    }
  }

  [Column(IsVersion = true)]
  private Binary _version;

  public event PropertyChangingEventHandler PropertyChanging;

  public event PropertyChangedEventHandler PropertyChanged;

  void RaisePropertyChanged(string propName)
  {
    if (PropertyChanged != null)
    {
      PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }
  }

  void RaisePropertyChanging(string propName)
  {
    if (PropertyChanging != null)
    {
      PropertyChanging(this,
        new PropertyChangingEventArgs(propName));
    }
  }
}

This new class is implemented just like the Game class (because we want it to allow change management). To be able to save it in the database, we need to expose it on our context class as well as on a public field:

public class AppContext : DataContext
{
  public AppContext()
    : base("DataSource=isostore:/myapp.sdf;")
  {
  }

  public Table<Game> Games;

  public Table<Publisher> Publishers;
}

At this point you could create, edit, query, and delete both the Game and Publisher objects. But what you really want is to be able to relate the two objects to each other. That’s where associations come in.

To add an association, you need to start by having a column on the Game class that represents the publisher’s primary key:

[Table]
public class Game : INotifyPropertyChanging, INotifyPropertyChanged
{
  // ...

  [Column]
  internal int _publisherId;

}

This new column is used to hold the ID of the related publisher for this particular game. The data is not public (it is internal in this case) because users of this class won’t set this value explicitly. Instead, you will create a nonpublic member that will store an object called an EntityRef. The EntityRef class is a generic class that wraps a related entity:

[Table]
public class Game : INotifyPropertyChanging, INotifyPropertyChanged
{
  // ...

  [Column]
  internal int _publisherId;

  private EntityRef<Publisher> _publisher;
}

The EntityRef class is important here because it will also support lazy loading of the related entity so that large object graphs aren’t loaded accidentally. But the real magic of linking the column and the EntityRef happens in the public property for the related entity:

[Table]
public class Game : INotifyPropertyChanging, INotifyPropertyChanged
{
  // ...

  [Column]
  internal int _publisherId;

  private EntityRef<Publisher> _publisher;

  [Association(IsForeignKey = true,
    Storage = "_publisher",
    ThisKey = "_publisherId",
    OtherKey = "Id")]
  public Publisher Publisher
  {
    get { return _publisher.Entity; }
    set
    {
      // Handle Change Management
      RaisePropertyChanging("Publisher");
        
      // Set the entity of the EntityRef
      _publisher.Entity = value;

      if (value != null)
      {
        // Set the foreign key too
        _publisherId = value.Id;
      }

      // Handle Change Management
      RaisePropertyChanged("Publisher");
    }
  }

}

There is a lot going on in this property, so let’s take it one piece at a time. First, let’s look at the Association attribute. This attribute has a number of parameters, but these are the basic ones to set. The IsForeignKey parameter tells the association that this is a foreign key relationship. The Storage parameter describes the name of the class’s member that holds the EntityRef for this association. The ThisKey and OtherKey are the columns of the keys on each side of the association. ThisKey refers to the name of the column on this class (Game); OtherKey refers to the column name on the other side of the association (Publisher).

When someone accesses this property, you will return the entity from within the EntityRef object as shown previously in the property getter.

Finally, the setter has a number of operations. The first and last operations in the setter handle the change management notification just like any column property on your table class. Then it takes the value of the property and sets it to the Entity inside the EntityRef object. Finally, if the value being set is not null, it sets the foreign key ID on the table class so that the column that represents the foreign key is set.

By doing all of this, you can have a one-to-many relationship between two table classes. But so far that association is only one-way. To complete the association, you might want to have a collection on the Publisher table class that represents all the games by that publisher.

Adding the other side of the relationship is similar, but in this case you need an instance of a generic class called EntitySet:

[Table]
public class Publisher :
  INotifyPropertyChanging, INotifyPropertyChanged
{
  // ...

  EntitySet<Game> _gameSet;

  [Association(Storage = "_gameSet",
    ThisKey = "Id",
    OtherKey = "_publisherId")]
  public EntitySet<Game> Games
  {
    get { return _gameSet; }
    set
    {
      // Attach any assigned game collection to the collection
      _gameSet.Assign(value);
    }
  }
}

The EntitySet class wraps around a collection of elements associated with a table class. In this case, the EntitySet wraps around a collection of games that belong to a publisher. As in the other side of the association, specifying the Storage, ThisKey, and OtherKey helps the context object figure out how the association is created. The only surprising thing is that when the setter on the Games property is called, it attaches whatever games are assigned to it to the set of Games. This is typically called by the context class only when executing a query.

Although not obvious, the construction of the _gameSet field isn’t shown. This needs to be done in the constructor:

[Table]
public class Publisher :
  INotifyPropertyChanging, INotifyPropertyChanged
{
  // ...

  public Publisher()
  {
    _gameSet = new EntitySet<Game>(
      new Action<Game>(this.AttachToGame),
      new Action<Game>(this.DetachFromGame));
  }

  void AttachToGame(Game game)
  {
    RaisePropertyChanging("Game");
    game.Publisher = this;
  }

  void DetachFromGame(Game game)
  {
    RaisePropertyChanging("Game");
    game.Publisher = null;
  }
}

In the constructor you must create the EntitySet. Note that in the constructor, you will also pass in two actions that handle attaching and detaching a game to and from the collection. The purpose of these two actions is to ensure that the individual games that are attached/detached also set or clear their association property. In addition, raising the PropertyChanging event helps the context object to be very efficient when the association is changing.

 
Others
 
- Windows Phone 8 : Databases and Storage (part 4) - Local Databases - Optimizing the Context Class
- Windows Phone 8 : Databases and Storage (part 3) - Local Databases - Getting Started
- Windows Phone 8 : Databases and Storage (part 2) - Storage - Serialization
- Windows Phone 8 : Databases and Storage (part 1) - Storage
- Active Directory 2008 : Creating Computers and Joining the Domain (part 3) - Offline Domain Join
- Active Directory 2008 : Creating Computers and Joining the Domain (part 2) - Joining a Computer to the Domain, Secure Computer Creation and Joins
- Active Directory 2008 : Creating Computers and Joining the Domain (part 1) - The Computers Container and OUs
- Exchange Server 2010 : Using the Exchange Management Shell
- Exchange Server 2010 : Using the Exchange Management Shell - Working with Cmdlets
- Exchange Server 2010 : Using the Exchange Management Shell - Using Windows PowerShell
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
Technology FAQ
- Is possible to just to use a wireless router to extend wireless access to wireless access points?
- Ruby - Insert Struct to MySql
- how to find my Symantec pcAnywhere serial number
- About direct X / Open GL issue
- How to determine eclipse version?
- What SAN cert Exchange 2010 for UM, OA?
- How do I populate a SQL Express table from Excel file?
- code for express check out with Paypal.
- Problem with Templated User Control
- ShellExecute SW_HIDE
programming4us programming4us