2. Agenda
ď§ Database Support in Windows Phone OS
ď§ LINQ to SQL
ď§ Queries
ď§ Inserts, updates, deletesâŚ
ď§ Database schema upgrades
ď§ Performance and best practices
10. Local Data Storage: Overview
ď§
ď§
ď§
Application
Settings File
App
Application
Files
Package
Manager
App Data Folder
WP7 Isolated
Storage APIs
Install
DB
Database file
DB Database
File (r/o)
11. Architecture
Custom Data
Context
App Objects
Identity
Management
Change
Tracking
Update
Processing
Object
Materialization
Core ADO.NET (System.Data)
SQLCE ADO.NET Provider (System.Data.SqlServerCe)
SQLCEDB
.Call System.Linq.Queryable.Select( .Call
System.Linq.Queryable.Where(
.Constant(Table(Wines)), '(.Lambda
#Lambda1)), '(.Lambda #Lambda2)) .Lambda
#Lambda1(db.Wines $w) { $w.Country ==
âUSA" } .Lambda #Lambda2(w.Country $w) {
$w.Name }
var query = from w in db.Wines
where w.Country == "USA"
select w.Name;
select Name
from Wines
where Country = "USA"
12. Objects, Objects, ObjectsâŚ
Design
time
ď§ Create object model: wines, varietals, vineyards, etc.
ď§ Decorate objects with attributes for persistence
Run
time
ď§ Create DataContext reference to database
ď§ Translate object model into a database file
ď§ Submit API persists changes to DB
Database
upgrade
ď§ Create new objects to enable new features
ď§ Use upgrade APIs to change DB
Varietals Wines
Vineyards WineMakers
Wines
PK WineID
Name
Description
RetailPrice
FK2 VarietalID
FK1 VineyardID
Vineyards
PK VineyardID
Name
Latitude
Longitude
Country
Varietals
PK VarietalID
Name
Winemaker
PK WinemakerID
FirstName
LastName
13. Database Creation: Example
// Define the tables in the database
[Table]
public class Wine : INotifyPropertyChanged, INotifyPropertyChanging
{
private string wineID;
private string name;
[Column(IsPrimaryKey=true)]
public string WineID
{
get { return wineID; }
set {
InvokePropertyChanging(new PropertyChangingEventArgs("WineID"));
wineID = value;
InvokePropertyChanged(new PropertyChangedEventArgs("WineID"));
}
}
[Column]
public string Name { ... }
...
}
Define Tables
14. Database Creation: Example
// Define the data context.
public partial class WineDataContext : DataContext
{
public Table<Wine> Wines;
public Table<Vineyard> Vineyards;
public WineDataContext(string connection) :
base(connection) { }
}
...
// Create the database from data context, using a connection
string
DataContext db = new WineDataContext("isostore:/wineDB.sdf");
if (!db.DatabaseExists())
db.CreateDatabase();
15. Using SQLMetal code generator tool
⢠Use Visual Studio or SQL Server Management
Studio visual designers to create a SQL Server
Compact Edition 3.5 database on Dev PC
⢠Start a Visual Studio Command Prompt
⢠Run the SQLMetal tool to generate
LINQ to SQL code file
⢠c:>Sqlmetal /code:northwindEntities.cs
/context:NorthwindDataContext
/pluralize northwind.sdf
⢠Include generated code in your Windows Phone project
⢠Few fixes required to get it to compile
16. Queries: Examples
// Create the database form data context, using a connection string
DataContext db = new WineDataContext("isostore:/wineDB.sdf");
// Find all wines currently at home, ordered by date acquired
var q = from w in db.Wines
where w.Varietal.Name == âShirazâ && w.IsAtHome == true
orderby w.DateAcquired
select w;
17. DB
Name Little
Penguin
Varietal Pinot Noir
AtHome False
Name Little
Penguin
Varietal Pinot Noir
AtHome True
Inserts/Updates/Deletes
⢠Itâs all about the DataContext
⢠Changes made against
the DataContext first
⢠Changes persisted
by calling SubmitChanges()
⢠SubmitChanges
⢠LINQ to SQL determines change set
and submits to DB
Name Little
Penguin
Varietal Pinot Noir
AtHome False
Name Yellow
Tail
Varietal Pinot
Noir
AtHome True
18. Inserts/Updates/Deletes
Insert Update
Wine newWine = new Wine
{
WineID = â1768",
Name = âWindows Phone
Syrah",
Description = âBold and
spicy"
};
db.Wines.InsertOnSubmit(newWine)
;
db.SubmitChanges();
Wine wine =
(from w in db.Wines
where w.WineID == â1768"
select w).First();
wine.Description = âHints of plum
and melon";
db.SubmitChanges();
21. Relationships
â˘Express one-many, one-one and many-many
relationships using EntitySet<T> and
EntityRef<T> columns
â˘In the relational database, a child table has a
column â the Foreign Key â that stores the
unique ID of a record in the parent table
Words
PK WordId
Word
Pronunciation
Definition
AlternateSpellings
Origin
Favorites
PK FavoriteId
FK1 WordId
History
PK HistoryItemId
FK1 WordId
AddedDate
22. Example: Parent Object
[Table]
public class Contact : INotifyPropertyChanged, INotifyPropertyChanging
{
// Fields
private EntitySet<Lead> leads = new EntitySet<Lead>();
[Association(Storage = "leads", OtherKey = "ContactID")]
public EntitySet<Lead> Leads
{
get { return this.leads; }
set {
InvokePropertyChanging(
new PropertyChangingEventArgs("Leads"));
this.leads.Assign(value);
InvokePropertyChanged(
new PropertyChangedEventArgs("Leads"));
}
}
23. Example: Child Object
[Table]
[Index (Name="ContactID_Idx", Columns="ContactID", IsUnique=false)]
public class Lead : INotifyPropertyChanged, INotifyPropertyChanging
{
private EntityRef<Contact> contact;
[Column]
public long ContactID {get; set; }
[Association(Storage = "contact", ThisKey = "ContactID", IsForeignKey=true)]
public Contact Contact
{
get { return this.contact.Entity; }
set {
InvokePropertyChanging(new PropertyChangingEventArgs("Contact"));
this.contact.Entity = value;
InvokePropertyChanged(new PropertyChangedEventArgs("Contact"));
if (value != null)
this.ContactID = value.ContactID;
}
}
24. Deletes
Delete
var contactsToDelete =
from Contact c in db.Contacts
where c.Company == âAppamundiâ
select c;
db.Contacts.DeleteAllOnSubmit
(contactsToDelete);
db.SubmitChanges();
25. Delete Child Objects First
var contactsToDelete = from Contact c in db.Contacts
where c.Company == âAppamundi"
select c;
foreach (Contact c in contactsToDelete)
{
db.Leads.DeleteAllOnSubmit(c.Leads);
}
db.Contacts.DeleteAllOnSubmit(contactsToDelete);
db.SubmitChanges();
30. LINQ to SQL Performance and Best Practices
⢠Keep change sets small
⢠Submit early and often to avoid data loss on app termination
⢠Use background threads
⢠Non-trivial operations will impact app responsiveness if done on UI thread
⢠Optimize read-only queries
⢠Set ObjectTrackingEnabled to minimize memory usage
⢠Use secondary indices for properties which you query often
31. LINQ to SQL Performance and Best Practices
⢠Populate large reference data tables in advance
⢠Create a simple project to prepopulate data in emulator
⢠Pull out database file using Isolated Storage explorer
⢠Use the right tool for the job
⢠Database for large or complex data sets
⢠IsolatedStorageSettings or basic files for small data sets
32. The information herein is for informational
purposes only an represents the current view of
Microsoft Corporation as of the date of this
presentation. Because Microsoft must respond
to changing market conditions, it should not be
interpreted to be a commitment on the part of
Microsoft, and Microsoft cannot guarantee the
accuracy of any information provided after the
date of this presentation.
Š 2012 Microsoft Corporation.
All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.
MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION
IN THIS PRESENTATION.
Editor's Notes
Local DatabaseAt the end of this module, students will be able to:Describe the implementation of database support in Windows Phone OS 7.1Program LINQ to SQL statements to select, create, delete and update objects in a local databaseDescribe best practices for programming LINQ to SQL on Windows Phone
LINQ to SQL in Windows OS 7.1So far in this module, you have learned how to store data in isolated storage using files and using the IsolatedStorageSettings API.In this section, you will learn how to store relational data in isolated storage.Â
LINQ to EverythingLINQ stands for Language INtegratedQuery, and is the ability to do queries on collections of objects using C# or VB language statements. LINQ enables queries on a wide variety of data sources. In Windows Phone 7.0, there was support for LINQ to Objects and LINQ to XML â effectively two âwide variety of data sourcesâ.That enables a lot of things, but in Mango LINQ support is expanded to cover a lot more data sources:LINQ to SQLLINQ to User Data, primarily contacts and calendarLINQ to OData (covered in the Networking module) â otherwise known as âLINQ to URLâ  Â
Complex SchemaWhen building the data access strategy for WP, these are the kind of app scenarios they are trying to support. First is the Complex Data Schema app. You can do this without a database, serialize into XML File or some binary format, store in Isolated Storage and away you go.In fact, this is one of the samples shipped with 7.0. However, as this gets more complex, add more tables and relationships, it rapidly gets much more complex. You rapidly run into performance problems, and complicated and unwieldy code. So although a shopping list is possible in 7.0, if you built it using a database it would be much easier to manage, much easier to expand and to add new features such as an additional search facility.Â
Reference DataAlthough a shopping list is âdoableâ in 7.0, an app such as a dictionary app with large amounts of reference data is much, much harder to do without a database.Youâd have to divide it up into smaller files, serialize them all to Isolated Storage, work out when to pull bits out of Isolated Storage when needed and to co-ordinate them all, all the time.Itâs a very, very difficult thing to do without a database. Clearly a scenario they wanted to go ahead and support in âMangoâ  Â
Web Service CacheA Dictionary is clearly a special case with a large amount of reference data stored locally on the phone â kind of a ânicheâ scenario. What will be more common is where you have a large reference database stored out on the cloud somewhere, possibly exposed by an OData service.On the phone you might want to cache some of that on the phone, possibly mash it up with some User Data, or some user-created data points on the phone to create the overall app experience.  Â
For demonstration notes please look in the âDemonstrationâ folder and open the corresponding Word document.Â
Database Support in Windows Phone 7.5In this next section, we will take a close look at how local database is supported in Windows Phone âMangoâ.Â
Local Data Storage: OverviewFirst thing to point out is that there are actually two locations on the phone within your âapp containerâ where data can be stored.Most people are familiar with IsolatedStorage, the sandboxed part of the phone where you can use File System APIs to store files and folders. Thereâs actually another location, called the AppData or the Install folder.Think of this where the contents of your XAP is exploded on installation.Everything in there is Read Only, and when you install an app update, everything in there is blown away and replaced with the new contents of your XAP.This is different from the Isolated Storage area, which is maintained on an app update so that any existing data in there is not destroyed. Now you can put databases in both of those places. Two new URI naming schemes have been introduced in Mango to allow you to identify the root folder when specifying the path to a database located in IsolatedStorage or in AppData:isostore:/{folder}/filename.ext â located in IsolatedStorageappdata:/{folder}/filename.ext â located in the AppData folderÂ
ArchitectureLooking at the technology stack used to implement local database support. [Ask how many people are familiar with LINQ to SQL on the desktop] The query shown top left is the type of code and type of query that your app will be doing. You execute statements that touch the database through a custom data context object that you create.Underneath that, there is the LINQ to SQL layer which manages the whole business of ORM (object to relational mapping), change tracking and so on. It constructs what is called an âexpression treeâ which is all that gobbledy-gook you see on the left, which fortunately your app does not have to worry about.Ultimately that is turned into a set of raw T-SQL statements that are executed by the SQLCE ADO.NET provider against the phone. Key differences between LINQ to SQL on the phone and that on the desktop:On the desktop you are primarily using LINQ to SQL statements like those you see at the top of the screen, but you also have this kind of âback doorâ facility to execute raw DDL and DML directly against the database (as we did on Windows Mobile), to access some ADO.NET objects. On Phone, you cannot program against the ADO.NET layer and cannot do this â they decided not to allow any pollution of the beautiful âobject onlyâ model of the phone. Youâll be writing exclusively LINQ to SQL statements.Â
Objects, objects, objectsâŚLINQ to SQL is an ORM. Since the early days of ORM, one of those religious war issues has been, do you map from the relations to the objects, or from the objects to the relations?With Mango, itâs you map from the Objects to the Relations. This is âCode Firstâ Entity mapping. You start by defining the data objects (or âentitiesâ) you want to persist in the database, and you decorate your objects with appropriate attributes to define keys, columns, tables.Then at runtime, the LINQ to SQL layer takes care of translating your annotated objects into the appropriate schema for relational tables and relationships in the database. It builds the database structure based on your annotated objects. As you use the app, you create, read, update and delete instances of your data objects and the database Submit APIs push those changes down to the database layer where they are persisted inside the database.  Â
Database Creation: ExampleYou start by defining the data classes in just the same way as if the objects are only going to be held in memory.You annotate the classes with the [Table] attribute on the class, and [Column] attributes on the public properties. There are additional qualifiers you can specify on the attributes, such as the IsPrimaryKey=true qualifier used here to specify that the WineID column is the primary key for this table.Notice that this class implements INotifyPropertyChanged which as you learnt in the DataBinding covered earlier in the course, is the interface that data objects that participate in Silverlight data binding must implement. Notice also that it implements another interface, INotifyPropertyChanging. This is very similar to INotifyPropertyChanged in that it consists of just a single event, this time the PropertyChanging event.You should implement this pattern of firing the PropertyChanging event just before you change the value of a property in a data class, and fire PropertyChanged just after. When you do this with LINQ to SQL, it allows the change tracking layer to optimize its operations and easily keep track of which columns have changed. If you do not do this, change tracking will still work but LINQ to SQL has to keep a snapshot of every object that it fetches from the database in order to figure out what has changed by doing a field by field comparison when you call the SubmitChanges method of the data context.Note that the code on this slide does not show the InvokePropertyChanging or InvokePropertyChanged methods of this class, which are local methods of the form:private void InvokePropertyChanging(PropertyChangingEventArgsargs){ if (PropertyChanging != null) {PropertyChanging(this, args); }}private void InvokePropertyChanged(PropertyChangedEventArgsargs){ if (PropertyChanged != null) {PropertyChanged(this, args);}}
Database Creation: Example Data ContextAfter you have defined all your classes that will be persisted as tables in your database, you must then create a custom data context.You create this class which inherits from System.Data.Linq.DataContext. It can be quite simple. You must define public properties on the class of type System.Data.Linq.Table<T> which defines the tables in the database. You have one property of this kind for each data class you have created and annotated.The other thing you must do is to create a constructor which takes the connection string to the database and which calls the similar constructor of the base class.At runtime, you can create the physical database using code similar to that shown on the slide. At the very least, the connection string must specify the path to the physical database, such as isostore:/wine.sdf as shown here.[Note that you do not have to create a new database at runtime, You could ship a read-only populated database in your Xap and open it for read-only access by specifying a path using the appdata:/ root. Or you could ship a partly-populated or empty database in your Xap, and then copy it across to the IsolatedStorage area at runtime to use as a read/write database.]The connection string can be used to specify database configuration values. For example, the connection string can specify whether the database should be encrypted and password-protected. In a connection string, individual parameters are separated by semicolons and parameter values are placed within single quotes. Some parameters are applicable only to creating the database; after the database has been created, those parameters are ignored.See the topic Local Database Connection Strings for Windows Phone in MSDN documentation for full details of the connection string options.
Not Really Supported: SQLMetalMicrosoft recommends that you design your database using the âcode-firstâ approach just described over the previous few slides.However, there is another way of creating the class files and your data context class which is favored by many developers. As the database used on Windows Phone is compatible with SQL Server Compact Edition v3.5, you can create a database using the graphical designer found in SQL Server Management Studio, or the server explorer tools found in Visual Studio.When you have completed your database design using one or both of those tools, you can run the SQLMetal command line tool against your database file and it can generate the class files and data context to match the design of the database you have created.Include the tool generated code in your project. When you compile the tool generated code inside a Windows Phone project, you will get a few compile time errors as the tool-generated code has a few incompatibilities with the version of .NET supported on the phone, but these corrections are simple to make. The SQLMetal tool is included in the Windows SDK that is installed with Visual Studio. By default, the file is located at drive:\Program Files (X86)\Microsoft SDKs\Windows\v7.01\bin. If you do not install Visual Studio, you can also get the SQLMetal file by downloading the Windows SDK.
Queries: Examples We are not going into too much detail on all the types of queries you can do, all the tips and tricks. Apart from the limitations already mentioned (no DMO, ADO.NET), pretty much all of the stuff you do with desktop LINQ to SQL transfers across, so there is plenty of documentation available on the web which is mostly relevant to Windows Phone. The key thing to observe here is that you perform LINQ queries against one of the table properties of your data context object: db.Wines in this example. The table property exposes the collection of objects that you are querying. When you enumerate the result of the query, the LINQ to SQL layer takes care of reading the selected objects out of the underlying database and materializing them as in memory objects. There is a CompiledQuery capability where if you are repeating a query multiple times, you can create a CompiledQuery object which prepares the corresponding SQL Commands up front giving you a performance boost when you repeat the query.  Â
Inserts/Updates/DeletesMany times you will be just doing queries against your database, but in any kind of interesting app, youâre going to be making changes as well.As far as that goes, itâs important to understand that itâs all about the DataContext. The DataContext is not only the ORM glue that transforms relational tables into objects and back again, but it is also responsible for change tracking. So your application code makes changes against the objects exposed by the DataContext, but those changes are not automatically written back to the underlying persistent datastore. So the DataContext also acts as a data cache for objects it has fetched from the database. That is done when you call SubmitChanges â it is important to remember to do this, otherwise next time your user opens the app they will get the unchanged data, and not what they entered in last time.  Â
Inserts/Updates/Deletes â ExamplesTi insert a new object into the database, you create a new instance of the object (for now only held in memory) and set properties on it. Then call the InsertOnSubmit() or InsertAllObSubmit() method of the relevant Table property exposed by the data context. At this point you have just asked the data context to perform the insert the next time you ask it to SubmitChanges(). In this example, you call SubmitChanges() in the very next statement, but you could buffer up many different changes and submit them all together. When you do that, the changes are applied within the scope of a transaction: either they are all applied or none of them are.To perform an update, first select the required objects out of the database. Then update properties on those objects. The data context takes care of the change tracking, so when you later call SubmitChanges() it makes the relevant updates in the underlying database.  Â
Inserts/Updates/Deletes â Delete ExampleThe process to delete an object or objects is similar to updating: first select the required objects from the database, then call DeleteOnSubmit() for a single object, or DeleteAllOnSubmit() for a collection of objects. The deletions are applied to the database when you call the data context SubmitChanges() method.The key thing to remember with deletes is that underneath all this, this is a database and so you have to be thinking about dependencies. In the next few slides we will look at some of the things you must consider if deleting a database object that has a relationship with records in another table.  Â
For demonstration notes please look in the âDemonstrationâ folder and open the corresponding Word document.Â
RelationshipsIf your application needs only a few collections of objects that are independent of each other, you can easily achieve your data persistence needs for your application by just serializing and deserializing the objects to and from a file in isolated storage.However, the key strength of a relational database is its ability to represent relationships between records. You can define a relationship between for example a Customer and their Orders by putting a column in the Orders table which holds the CustomerID of the related Customer record. The Customer âownsâ a collection of Orders, and you can easily find the Customer record for any Order by reading the CustomerID value out of the Order record and using it to look up the corresponding Customer record. The CustomerID column in this example is described as a Foreign Key to the Customer Table. A developer can program the relational database to enforce a constraint that prevents you from creating an Order record that contains an invalid CustomerID record.In the example on this slide, the Favorites table contains a list of favorite words from the Words table. It has a foreign key column, WordID, that just stores the key value of the Word record that the user has selected to put into their favorites.Â
Example: Parent ObjectThe code shows a class Contact which has a public property Leads of type EntitySet<Lead>. This property represents a one to many relationship between a Contact record (the âParentâ) and a collection of Lead objects (the âChildâ objects). This is often described as a Parent-Child relationship.You use the [Association] attribute to annotate a property that references records in a different table. The Storage = âleadsâ property sets the private storage field leads to store the value from the column. The OtherKey = âContactIDâ property names the column in the Leads table that is the foreign key field in that table.In your code, to get the collection of child Lead objects for a given Contact instance, you simply get the contactsâ Leads property. For example: EntitySet<Lead> theleads = myContact.Leads;Â Â
Example: Child ObjectOn the other side of the one-to-many relationship, you define a backing field of type EntityRef<T> which will store the reference â or pointer â back to the parent record. This is the following field shown in the code:private EntityRef<Contact> contact;You then define a public property which returns the type of the parent record â Contact in this case. Note the code in the setter of this property: you return the real parent object by getting the Entity property of the EntityRef<T> backing field. You must also define a column to store the key value of the parent record. In this example, that is the ContactID column. In the setter of the Contact property, you must explicitly set the key value of the parent Contact record into the ContactID column as shown in this code sample on the slide.Annotate the property that connects back to the parent using the [Association] attribute. The storage property names the backing field (contact)used to store the value of this property. The ThisKey property names the column in this class that stores the key value (ContactID), and the IsForeignKey=true property denotes that this represents a foreign key relationship.In this kind of relationship, the parent record (Contact) is not stored as part of the child record (Lead). The child record simply maintains a pointer back to the parent by storing the key value of the parent in one of its columns. However, the relationship is rather more than that: the database maintains a foreign key constraint that prevents you from inserting a child record that does not have a valid key value for a parent record.One other thing to note: notice how a secondary index is defined on the ContactID column by means of the [Index] attribute at the top of the class?. Given that we have the relationship between Lead objects and Contact objects defined, it stands to reason that in our code there will probably be numerous occasions where we will want to select all the Lead objects for a given Contact. If this secondary index did not exist, the database engine would have to do a complete scan of all the Lead objects in the database to identify those which had the required ContactID. This operation, knoe=wn as a âTable Scanâ is very inefficient when a table contains many records. With an index defined, the required records can be identified very efficiently.
DeletesThe other thing the foreign key constraint gives you is that it prevents you from deleting a parent record when there are existing child records that reference it via a foreign key constraint. If you try to do this, your code will throw an exception.The key thing to remember with deletes is that underneath all this, this is a database and so you have to be thinking about dependencies.  Â
Delete Child Objects FirstThe answer is to make sure you delete all the child records first before you try to delete the parent. NOTE: In many relational databases it is possible to define a foreign key relationship with a CASCADE DELETE=true qualifier that causes the child objects in a foreign key relationship to be automatically deleted if the parent record is deleted. There is no CASCADE DELETE support on foreign keys defined through attributes in LINQ to SQL, which is why you must code the deletion of child objects explicitly.  Â
For demonstration notes please look in the âDemonstrationâ folder and open the corresponding Word document.
Database Schema UpgradesOver time, the requirements for your database are going to change as you add new features, so you will need to consider how you upgrade an existing database when a user installs a new version of your application. One change from desktop LINQ to SQL is that you donât have access to raw DDL and DML statements, so one thing that will change from desktop is the method of applying schema upgrades. This is achieved by the DatabaseSchemaUpdater API that allows you to make additive changes to a database such as adding columns, tables and keys. You use the Upgrade APIs to apply those changes and the database layer makes the appropriate changes to the underlying database.  You can set a version number as part of that schema upgrade â you can query back when you launch the app to determine if a database needs to be updated.Â
Database Schema UpgradesTo upgrade a database, you first change the class definitions to add columns and/or indices, and you define new classes for any new tables. You also update the code of your custom data context for any new tables.Then at runtime in the initialization logic of your application, create an instance of DatabaseSchemaUpdater by calling the CreateDatabaseSchemaUpdater() method of your data context. Use this to check the current schema version as shown in this code snippet, and if the database needs upgrading, call the DatabaseSchemaUpdaterAddTable(), AddColumn() and AddIndex() methods to apply the corresponding schema changes.Donât forget to set the DatabaseSchemaVersion property to the version of the upgraded database as well!Â
Best PracticesThis section gives some general advice on best practices with persistent data storage.Â
LINQ to SQL Performance and Best PracticesThereâs a lot of info out there on LINQ to SQL on the desktop and most of that applies to LINQ to SQL on the phone, so we advise you to look at that for general info. In particular, as already mentioned use background threads for large data set retrieval. If you are retrieving objects that you are not going to change, set the ObjectTrackingEnabled property on your data context to false before issuing your LINQ select statement to turn off the change tracking overhead. For example: context.ObjectTrackingEnabled = false; Make sure you create secondary indexes on columns in your tables that you use frequently to filter records when selecting them. This can make a huge impact on record selection performance. Phone-specific tips:Keep changesets as small as possible, because a phone app will be active for small periods of time in general. If you cache large changesets in your DataContext with the plan to persist it in OnDeactivated, thereâs a good chance you wonât be able to complete in time before the OS kills your app because itâs taking too long to deactivate.
LINQ to SQL Performance and Best PracticesIf you have large reference data tables, consider populating them in advance and shipping them with the project. You can do this by creating a dummy Windows Phone application specifically to load the reference data and then use the Isolated Storage Explorer tool to pull the database off the device or emulator so you can include it as content in your application project.Alternatively, you can create a desktop application that uses SQL server Compact 3.5 and use that to populate the database.Finally, use the right tool for the job. Use LINQ to SQL for complex data models with relational characteristics, or for very large data sets that are unmanageable in flat files. But use flat files stored in isolated storage if your data storage requirements are relatively simple.Â