Andy Wigley APPA Mundi @andy_wigley [email protected] New Data Features in “Mango”: SQL...
-
Upload
cornelia-oliver -
Category
Documents
-
view
214 -
download
1
Transcript of Andy Wigley APPA Mundi @andy_wigley [email protected] New Data Features in “Mango”: SQL...
Andy WigleyAPPA Mundi
@andy_wigley
http://bit.ly/andywigley
New Data Features in “Mango”:SQL Server Compact and User Data Access
LINQ to SQL
• Overview– Architecture– Code-first development
• Implementation details– Queries– Inserts, updates, deletes…– Database schema upgrades
• Performance and best practices
LINQ to User Data
• Overview– End-user consent– Supported account types
• Implementation details– Querying contacts– Querying appointments
• Performance and best practices
Session Outline
Complex Schema
• Numerous relationships and constraints
• Example: Shopping List– 7 tables– 100s of records– 5 foreign keys
ItemReferenceData
PK ItemId
ItemName ItemDescriptionFK1 CategoryId
Categories
PK CategoryId
CategoryName
Lists
PK ListId
ListName
ListItems
PK ListItemId
ListItemNameFK1 ListId Quantity Category DescriptionFK2 StoreId
Stores
PK StoreId
StoreName StoreLocationLat StoreLocationLong StoreAddressLine1 StoreAddressLine2 StoreAddressCity StoreAddressState StoreAddressCountry StoryAddressZip
Favorites
PK FavoriteItemId
FavoriteItemName FavoriteItemCategory FavoriteItemQuantity FavoriteItemDescriptionFK1 FavoriteItemListId FavoriteItemPhoto
History
PK HistoryItemId
HistoryItemName HistoryItemCategory HistoryItemQuantity HistoryItemDescriptioin HistoryItemDateAddedFK1 HistoryItemListId HistoryItemPhoto
Reference Data
• Huge amounts of static reference data
• Example: dictionary app– 3 tables– 1 table with 500k rows
Words
PK WordId
Word Pronunciation Definition AlternateSpellings Origin
Favorites
PK FavoriteId
FK1 WordId
History
PK HistoryItemId
FK1 WordId AddedDate
Web Service Cache
• Fetch reference data from cloud
• Cache locally• Combine with user-specific
data
Cloud Service
Windows Phone
Service Cache
User Data
User Data
• Filter contacts– Birthdays in the next
month
• Query all appointments– Find an available time for
a meeting
Filter
Local Data Storage: OverviewApps store private data in Isolated Storage Settings and properties in the app dictionary Unstructured data in Isolated Storage files Structured data in database files
ApplicationSettings File
AppCreates/Managesfiles and settings
ApplicationFiles
Iso Store Folder
Creates root foldersandboxed to AppPackage Manager
App Data Folder
WP7 Isolated Storage APIs
Install
DB
Database file
DB DatabaseFile (r/o)
ArchitectureYour AppCustom Data
ContextApp
Objects
System.Data.Linq
Identity Management
Change Tracking
Update Processing
Object Materialization
Microsoft.Phone.Data.Internal
Core ADO.NET (System.Data)
SQLCE ADO.NET Provider (System.Data.SqlServerCe)
SQL CE DB
.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 Namefrom Wineswhere Country = “USA”
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 RetailPriceFK2 VarietalIDFK1 VineyardID
Vineyards
PK VineyardID
Name Latitude Longitude Country
Varietals
PK VarietalID
Name
Winemaker
PK WinemakerID
FirstName LastName
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) { }
}
// Define the tables in the database[Table]public class Wine{
[Column(IsPrimaryKey=true]public string WineID { get; set; }[Column]public string Name { get; set; }……
}
// Create the database form data context, using a connection stringDataContext db = new WineDataContext("isostore:/wineDB.sdf");if (!db.DatabaseExists()) db.CreateDatabase();
Queries: Examples
// Create the database form data context, using a connection stringDataContext db = new WineDataContext("isostore:/wineDB.sdf");
// Find all wines currently at home, ordered by date acquiredvar q = from w in db.Wines
where w.Varietal.Name == “Shiraz” && w.IsAtHome == true orderby w.DateAcquired select w;
DB
DataContextName 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
Your App Code
Name Yellow Tail
Varietal Pinot Noir
AtHome True
Inserts/Updates/DeletesInsert 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();
Inserts/Updates/DeletesDelete
var vineyardsToDelete = from Vineyards v in db.Vineyardswhere v.Country == “Australia”select v;
db.Vineyards.DeleteAllOnSubmit(vineyardsToDelete);
db.SubmitChanges();
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
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")); } }
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; } }
DeletesDelete
var vineyardsToDelete = from Vineyards v in db.Vineyardswhere v.Country == “Australia”select v;
db.Vineyards.DeleteAllOnSubmit(vineyardsToDelete);
db.SubmitChanges();
Foreign key constraint will cause exception here if Wines associated with the Vineyards are not deleted first
Delete Child Objects Firstvar vineyardsToDelete = from Vineyards v in db.Vineyards
where v.Country == “Australia" select v;
foreach (Vineyards v in vineyardsToDelete){ db.Wines.DeleteAllOnSubmit(v.Wines);}
db.Vineyards.DeleteAllOnSubmit(vineyardsToDelete);db.SubmitChanges();
Database Schema Upgrades• DatabaseSchemaUpdater allows simple upgrades
on your existing DB• Supports adding
– Tables– Columns– Indices– Associations/foreign keys
• Schema updates are transactional
Database Schema UpgradesWineDataContext wineDC = new WineDataContext(App.WineDBConnectionString);
DatabaseSchemaUpdater dsu = wineDC.CreateDatabaseSchemaUpdater();
if (dsu.DatabaseSchemaVersion == 1){
dsu.AddColumn<Wine>("BottleType");dsu.DatabaseSchemaVersion = 2;
dsu.Execute();}
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
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
New and updated APIs in “Mango”
• Chooser Tasks related to user data– EmailAddressChooserTask– PhoneNumberChooserTask– AddressChooserTask
• Microsoft.Phone.UserData for direct access– Contacts– Appointments
AddressChooserTaskprivate AddressChooserTask addressChooserTask;
// Constructorpublic MainPage(){ this.addressChooserTask = new AddressChooserTask(); this.addressChooserTask.Completed += new
EventHandler<AddressResult>( addressChooserTask_Completed);
}
private void addressChooserTask_Completed(object sender, AddressResult e){ if (null == e.Error && TaskResult.OK == e.TaskResult) {
... = e.DisplayName;
... = e.Address; }}
Contacts and Appointments
• Important points– Contacts and Appointments APIs are read
only– Third party social network data cannot be
shared
Contacts/Appointments Data Shared Contact Name
and PictureOther contact data Appointments/Events
Windows Live Social YES YES YES
Windows Live Rolodex(user created and SIM import)
YES YES n/a
Exchange accounts(corporate plus Google, etc.)
YES YES YES
Operator Address Books YES YES n/a
Facebook YES NO NO
Other networks in the People Hub (e.g., Twitter)
NO NO NO
Contacts: Hello, World!Contacts contacts = new Contacts();
contacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>((sender, e) => { ... = e.Results; });
// E.g. search for all contactscontacts.SearchAsync(string.Empty, FilterKind.None, null);
filter expression(not a regex)
Filter kind: name, email , phone or pinned to start)
state
// E.g. search for all contacts with display name matching "ja"contacts.SearchAsync("ja", FilterKind.DisplayName, null);
Appointments: Hello, World!Appointments appointments = new Appointments();
appointments.SearchCompleted += new EventHandler<AppointmentsSearchEventArgs>((sender, e) => { ... = e.Results; });
// E.g. get next appointment (up to 1 week away)appointments.SearchAsync(DateTime.Now, DateTime.Now + TimeSpan.FromDays(7), 1, null);
start date and time
Maximum items to return stateend date and time
Performance and Best Practices• Be responsible
– Your privacy policy should cover how you use the user’s contact information
• Keep out of the way– Users have widely varying contact list sizes – Your UI should handle delays gracefully
• Don’t let data get stale– Data returned is a snapshot– Refresh state when reasonable
© 2008 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. The information herein is for informational purposes only and 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. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.