Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update: Part 2: Rich Data Query
Continuing in our discussion of Silverlight 3 and the brand new update to .NET RIA Services and the update the example from my Mix09 talk “building business applications with Silverlight 3”.
You can watch the original video of the full session
The demo requires (all 100% free and always free):
- VS2008 SP1 (Which includes Sql Express 2008)
- Silverlight 3 RTM
- .NET RIA Services July '09 Preview
Also, download the full demo files and check out the running application.
Today, we will talk about Rich Data Query.
Rich Data Query
Next up, let’s talk about data query. Nearly every business application deals with data. Let’s look at how to do this with .NET RIA Services. We will start out in the web project. For this example I will use an Entity Framework data model, but RIA Services works great with any form of data from plain olld CLR objects to an xml file, to web services to Linq to Sql. For starters, let’s build an Entity Framework model for our data. For this walk through, we will start simply…
I updated the pluralization of the entity name
Now, how are we going to access this data from the SL client? Well, traditionally many business applications have started out as 2-tier apps. That has a number of problems around scaling and flexibility… and more to the point it just doesn’t work with the Silverlight\web client architecture.
So developers are thrust into the n-tier world. .NET RIA Services make it very easy to create scalable, flexible n-tier services that builds on WCF and ADO.NET Data Services.
These .NET RIA Services model your UI-tier application logic and encapsulate your access to varies data sources from traditional relational data to POCO (plain old CLR objects) to cloud services such as Azure, S3, etc via REST, etc. One of the great thing about this is that you can move from an on premises Sql Server to an Azure hosted data services without having to change any of your UI logic.
Let’s look at how easy it is to create these .NET RIA Services.
Right click on the server project and select the new Domain Service class
In the wizard, select your data source. Notice here we could have chosen to use a Linq2Sql class, a POCO class, etc, etc.
In the SuperEmployeeDomainService.cs class we have stubs for all the CRUD method for accessing your data. You of course should go in and customize these for your domain. For the next few steps we are going to use GetSuperEmployees(), so I have customized it a bit.
public IQueryable<SuperEmployee> GetSuperEmployees()
{
return this.Context.SuperEmployeeSet
.Where(emp=>emp.Issues>100)
.OrderBy(emp=>emp.EmployeeID);
}
Now, let’s switch the client side. Be sure to build the solution so you can access it from the client directly. These project are linked because we selected the “ASP.NET enable” in the new project wizard.
Drag the DataGrid off the toolbox… notice this works with any control..
In HomePage.Xaml add
<data:DataGrid x:Name="dataGrid1" Height="500"></data:DataGrid>
And in the code behind add MyApp.Web… notice this is interesting as MyApp.Web is defined on the server… you can now access the client proxy for the server DomainServices locally
1: var context = new SuperEmployeeDomainContext();
2: dataGrid1.ItemsSource = context.SuperEmployees;
3: context.Load(context.GetSuperEmployeesQuery());
In line 1, we create our SuperEmployeesDomainContext.. this is the client side of the SuperEmployeesDomainService. Notice the naming convention here…
In line 2, we are databinding the grid to the SuperEmployees.. then in line 3 we are loading the SuperEmployees, that class the GetSuperEmployees() method we defined on the server. Notice this is all async of course, but we didn’t have to deal with the complexities of the async world.
The result! We get all our entries back, but in the web world,don’t we want to do paging and server side sorting and filtering? Let’s look at how to do that.
First, remove the code we just added to codebehind.
Then, to replace that, let’s add a DomainDataSource. You can just drag it in from the toolbox:
Then edit it slightly to get:
1: <riaControls:DomainDataSource x:Name="dds"
2: AutoLoad="True"
3: QueryName="GetSuperEmployeesQuery"
4: LoadSize="20">
5: <riaControls:DomainDataSource.DomainContext>
6: <App:SuperEmployeeDomainContext/>
7: </riaControls:DomainDataSource.DomainContext>
8: </riaControls:DomainDataSource>
Notice in line 3, we are calling that GetSuperEmployeesQuery method from the DomainContext specified in line 6.
In line 4, notice we are setting the LoadSize to 20.. that means we are going to download data in batches of 20 at a time.
Now, let’s bind it to a the DataGrid and show a little progress indicator (that you can get in the sample)..
1: <activity:Activity IsActive="{Binding IsBusy, ElementName=dds}"
2: VerticalAlignment="Top"
3: HorizontalAlignment="Left"
4: Width="900" Margin="10,5,10,0">
5: <StackPanel>
6: <data:DataGrid x:Name="dataGrid1" Height="300" Width="900"
7: ItemsSource="{Binding Data, ElementName=dds}">
8: </data:DataGrid>
9: <data:DataPager PageSize="10" Width="900"
10: HorizontalAlignment="Left"
11: Source="{Binding Data, ElementName=dds}"
12: Margin="0,0.2,0,0" />
13: </StackPanel>
14: </activity:Activity>
In line 6, there is a datagrid, that is bound to the DDS.Data property (in line 7). Then we add a DataPager in line 9, that is bound to the same datasource. this gives us the paging UI. Notice in line 9 we are setting the display to 10 records at a time. Finally we wrap the whole thing in an ActivityControl to show progress.
The cool thing is that the ActivityControl, the DataGrid and the DataPager can all be used with any datasource such as data from WCF service, REST service, etc.
Hit F5, and you see..
Notice we are loading 20 records at a time, but showing only 10. So advancing one page is client only, but advancing again we get back to the server and load the next 20. Notice this all works well with sorting as well. And the cool thing is where is the code to handle all of this? Did i write in on the server or the client? neither. Just with the magic of linq, things compose nicely and it i just falls out.
I can early add grouping..
<riaControls:DomainDataSource.GroupDescriptors>
<datagroup:GroupDescriptor PropertyPath="Publishers" />
</riaControls:DomainDataSource.GroupDescriptors>
Let’s add filtering… First add a label and a textbox..
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="Origin: "></TextBlock>
<TextBox x:Name="originFilterBox" Width="75" Height="20"></TextBox>
</StackPanel>
and then these filter box to our DomainDataSource….
<riaControls:DomainDataSource.FilterDescriptors>
<datagroup:FilterDescriptorCollection>
<datagroup:FilterDescriptor PropertyPath="Origin"
Operator="StartsWith">
<datagroup:ControlParameter PropertyName="Text"
RefreshEventName="TextChanged"
ControlName="originFilterBox">
</datagroup:ControlParameter>
</datagroup:FilterDescriptor>
</datagroup:FilterDescriptorCollection>
</riaControls:DomainDataSource.FilterDescriptors>
When we hit F5, we get a filter box, and as we type in it we do a server side filtering of the results.
Now, suppose we wanted to make that a autocomplete box rather an a simple text box. The first thing we’d have to do is get all the options. Notice we have to get those from the server (the client might not have them all because we are doing paging, etc). To do this we add a method to our DomainService.
public class Origin
{
public Origin() { }
[Key]
public string Name { get; set; }
public int Count { get; set; }
}
and the method that returns the Origins…
public IQueryable<Origin> GetOrigins()
{
var q = (from emp in Context.SuperEmployeeSet
select emp.Origin).Distinct()
.Select(name => new Origin
{
Name = name,
Count = Context.SuperEmployeeSet.Count
(emp => emp.Origin.Trim() == name.Trim())
});
q = q.Where(emp => emp.Name != null);
return q;
}
Now we need to add the autocomplete control from the Silverlight 3 SDK. Replace the textbox with this:
<input:AutoCompleteBox x:Name="originFilterBox" Width="75" Height="30"
ValueMemberBinding="{Binding Name}"
ItemTemplate="{StaticResource OriginsDataTemplate}" >
</input:AutoCompleteBox>
Then we just need to add a little bit of code behind to load it up.
var context = dds.DomainContext as SuperEmployeeDomainContext;
originFilterBox.ItemsSource = context.Origins;
context.Load(context.GetOriginsQuery());
Hitting F5 gives us this…
Validating Data Update
Now – that was certainly some rich ways to view data, but business apps need to update data as well. Let’s look at how to do that. First replace all the xaml below the DDS with this… it gives us a nice master-details view.
1: <StackPanel Style="{StaticResource DetailsStackPanelStyle}">
2:
3: <activity:Activity IsActive="{Binding IsBusy, ElementName=dds}">
4: <StackPanel>
5: <StackPanel Orientation="Horizontal" Margin="0,0,0,10">
6: <TextBlock Text="Origin: " />
7:
8: <input:AutoCompleteBox x:Name="originFilterBox" Width="338" Height="30"
9: ValueMemberBinding="{Binding Name}"
10: ItemTemplate="{StaticResource OriginsDataTemplate}" />
11: </StackPanel>
12:
13: <data:DataGrid x:Name="dataGrid1" Height="380" Width="380"
14: IsReadOnly="True" AutoGenerateColumns="False"
15: HorizontalAlignment="Left"
16: HorizontalScrollBarVisibility="Disabled"
17: ItemsSource="{Binding Data, ElementName=dds}"
18: >
19: <data:DataGrid.Columns>
20: <data:DataGridTextColumn Header="Name" Binding="{Binding Name}" />
21: <data:DataGridTextColumn Header="Employee ID" Binding="{Binding EmployeeID}" />
22: <data:DataGridTextColumn Header="Origin" Binding="{Binding Origin}" />
23: </data:DataGrid.Columns>
24: </data:DataGrid>
25:
26: <data:DataPager PageSize="13" Width="379"
27: HorizontalAlignment="Left"
28: Source="{Binding Data, ElementName=dds}"
29: Margin="0,0.2,0,0" />
30:
31: <StackPanel Orientation="Horizontal" Margin="0,5,0,0">
32: <Button Content="Submit" Width="105" Height="28"
33: />
34:
35:
36: <!--new emp button here-->
37:
38:
39: </StackPanel>
40:
41: </StackPanel>
42: </activity:Activity>
43:
44: <StackPanel Margin="35,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Height="498" >
45: <dataControls:DataForm x:Name="dataForm1" Height="393" Width="331"
46: VerticalAlignment="Top"
47: Header="Product Details"
48: CurrentItem="{Binding SelectedItem, ElementName=dataGrid1}"
49: HorizontalAlignment="Left" >
50: <dataControls:DataForm.EditTemplate>
51: <DataTemplate>
52: <StackPanel>
53: <dataControls:DataField>
54: <TextBox Text="{Binding Name, Mode=TwoWay}" />
55: </dataControls:DataField>
56: <dataControls:DataField>
57: <TextBox Text="{Binding EmployeeID, Mode=TwoWay}" />
58: </dataControls:DataField>
59: <dataControls:DataField>
60: <TextBox Text="{Binding Origin, Mode=TwoWay}" />
61: </dataControls:DataField>
62: <dataControls:DataField>
63: <TextBox Text="{Binding Sites, Mode=TwoWay}" />
64: </dataControls:DataField>
65:
66: <dataControls:DataField>
67: <TextBox Text="{Binding Gender, Mode=TwoWay}" />
68: </dataControls:DataField>
69:
70: <dataControls:DataField>
71: <TextBox Text="{Binding Publishers, Mode=TwoWay}" />
72: </dataControls:DataField>
73: <dataControls:DataField>
74: <controls:DatePicker Text="{Binding LastEdit, Mode=OneWay}"></controls:DatePicker>
75: </dataControls:DataField>
76: <dataControls:DataField>
77: <TextBox Text="{Binding Issues, Mode=TwoWay}" />
78: </dataControls:DataField>
79: </StackPanel>
80: </DataTemplate>
81: </dataControls:DataForm.EditTemplate>
82:
83:
84: </dataControls:DataForm>
85:
86:
87:
88: <!--Permalink here-->
89:
90: </StackPanel>
91:
92:
93: </StackPanel>
Through line 35, this is pretty much the same as what we had.
Then in line 38, we add a DataForm control that gives us some nice way to view and edit a particular entity.
Hit F5
This looks like the traditional master-details scenario.
Notice as we change items they are marked as “Dirty” meaning they need to be submitted back to the server. You can make edits to many items, unmake some edits and the dirty marker goes away.
Now we need to wire up the submit button.
1: private void SubmitButton_Click(object sender, RoutedEventArgs e)
2: {
3: dataForm1.CommitEdit();
4: dds.SubmitChanges();
5: }
We first need to commit the item we are currently editing, then we just submit changes. This batches up the diffs and sends them back the server. and our Update method is called. Notice the dirty bit goes away.
Now, that is cool, but what about Data Validation? Well, “for free” you get type level validation (if the filed is typed as an int you and you enter a string you get an error).
Now let’s see if we can add a bit more. We do that by editing the SuperEmployeeDomainService.metadata.cs on the server. It is important to do it on the server so that the system does all the validations are done once for a great UX experience and then again on the server for data integrity. By the time your Update method is called on your DomainService you can be sure that all the validations have been done.
Here are some of the validations we can apply..
[ReadOnly(true)]
public int EmployeeID;
public EntityState EntityState;
[RegularExpression("^(?:m|M|male|Male|f|F|female|Female)$",
ErrorMessage = "Gender must be 'Male' or 'Female'")]
public string Gender;
[Range(0, 10000,
ErrorMessage = "Issues must be between 0 and 1000")]
public Nullable<int> Issues;
public Nullable<DateTime> LastEdit;
[Required]
[StringLength(100)]
public string Name;
Just rebuilding and running the app gives us great validation in the UI and in the middle tier.
Notice how I can navigate between the errors and input focus moves to the next one.
That was updating data, what about adding new data?
To do that, let’s explorer the new Silverlight 3 ChildWindow.
Right click on Views and add new Item Child Window
Let’s wire it up to show the default window. First add a button to the main form to display the childwindow we just created.
<Button Content="Add New"
Width="105" Height="28"
Margin="5,0,0,0" HorizontalAlignment="Left"
Click="AddNew_Click" ></Button>
Then wire it up..
private void AddNew_Click(object sender, RoutedEventArgs e)
{
var w = new AddNewWindow();
w.Show();
}
Notice it already has a OK and Cancel buttons and a close box that work great right out of the box. We just need to add a DataForm. Because we are bound to the same model, the DataForm will pick up all the same features as the update one we just looked at.
<dataControls:DataForm x:Name="newEmployeeForm" Height="393" Width="331"
VerticalAlignment="Top"
CommandButtonsVisibility="None"
Header="Add New Super Employee"
HorizontalAlignment="Left" >
<dataControls:DataForm.EditTemplate>
<DataTemplate>
<StackPanel>
<dataControls:DataField>
<TextBox Text="{Binding Name, Mode=TwoWay}" />
</dataControls:DataField>
<dataControls:DataField>
<TextBox Text="{Binding EmployeeID, Mode=TwoWay}" />
</dataControls:DataField>
<dataControls:DataField>
<TextBox Text="{Binding Origin, Mode=TwoWay}" />
</dataControls:DataField>
<dataControls:DataField>
<TextBox Text="{Binding Sites, Mode=TwoWay}" />
</dataControls:DataField>
<dataControls:DataField>
<TextBox Text="{Binding Gender, Mode=TwoWay}" />
</dataControls:DataField>
<dataControls:DataField>
<TextBox Text="{Binding Publishers, Mode=TwoWay}" />
</dataControls:DataField>
<dataControls:DataField>
<controls:DatePicker Text="{Binding LastEdit, Mode=OneWay}"></controls:DatePicker>
</dataControls:DataField>
<dataControls:DataField>
<TextBox Text="{Binding Issues, Mode=TwoWay}" />
</dataControls:DataField>
</StackPanel>
</DataTemplate>
</dataControls:DataForm.EditTemplate>
</dataControls:DataForm>
Now, in code behind we need to write this up by adding a class level field..
public SuperEmployee NewEmployee { get; set; }
..initializing the instance in the constructor
NewEmployee = new SuperEmployee();
NewEmployee.LastEdit = DateTime.Now.Date;
this.newEmployeeForm.CurrentItem = NewEmployee;
..handling the OK button
private void OKButton_Click(object sender, RoutedEventArgs e)
{
newEmployeeForm.CommitEdit();
this.DialogResult = true;
}
Great… now let’s commit this change locally.
void addNewWindow_Closed(object sender, EventArgs e)
{
var win = sender as AddNewWindow;
var context = dds.DomainContext as SuperEmployeeDomainContext;
if (win.DialogResult == true)
{
context.SuperEmployees.Add(win.NewEmployee);
}
}
From this, the Submit button will send this change to the server.
Comments
Anonymous
July 11, 2009
Excellent job, Brad. I am wonering how can i use the code developed before SL3 RTM?Anonymous
July 11, 2009
Awesome, just wondering how master/detail scenario can be handled?Anonymous
July 12, 2009
The comment has been removedAnonymous
July 12, 2009
Your thumbnails work, but the links to the full-size files are broken. They all point to locations like file:///C:/Users/brada/AppData/Local/Temp/WindowsLiveWriter-429641856/supfilesD1D2F6D/image[116].pngAnonymous
July 12, 2009
excellent article which I am ploughing thro' but one statement which I would like to query with you as I am new to Silverlight: '2-tier apps… and more to the point it just doesn’t work with the Silverlightweb client architecture' why wouldn't 2 tier work with Silverlight? The application logic surely could reside in the web service which could be 1..n tier? Presumably Google's Chrome OS will be an OS which simply renders UI and no more and client support for SL will have to work the same way?Anonymous
July 12, 2009
The comment has been removedAnonymous
July 13, 2009
I think the way RIA is going is great. Keep doing what your doing. But there is one concern that holds me from using it, and its not obvious until you get into the code. Using objects that have a couple levels of inheritance gets lost through the RIA serialization process. And so the objects get flattened. And that may be fine for most basic cases, but for some advanced applications, maintaining the inheritance hierarchy is important especially when you have a grid or a list of different types but are based on a the same base type. Now that being said, I love what you are doing. RIA is great. I'd just like to see it use more of a WCF type of serialization, which maintains the inheritance on the client. I know its the first version, I hope its addressed in version 2.Anonymous
July 15, 2009
OK - some of us (like 50%) don't use c#. Can we get the demo project in vb also? Else the utility of what you've put together here falls off radically.Anonymous
July 16, 2009
to "bell": Try www.myVBProf.com for some VB examples. PeterAnonymous
July 16, 2009
Why does Linq to SQL with RIA Services put the MyAppDomainContext in MyApp.Web.Services? To use a DomainDataSource the xmlns has to be like: xmlns:app="clr-namespace:MyApp.Web.Services"> where your's was: xmlns:App="clr-namespace:MyApp.Web"Anonymous
July 16, 2009
Tim -- i think we get the namespace from where the domainservice class is on the server... is yours in MyApp.Web.Services? You can have it in any namespace you'd like.Anonymous
July 18, 2009
Hi Brad, Great blogs on SL3 and RIA really useful - keep up the good work. I have onw problem though - I have been working on an app and needed a new item entry window. Everything is working fine except actually commiting the new item back to the database. Then I saw your sample, which is doing basically the same action - BUT I can't get that one to work either. Please can you confirm that your Add window does actually post back to the databse for SL3 RTM and July 09 RIA services - at least then I'll know its something to do with my setup! Thanks NicAnonymous
July 18, 2009
Hi Brad (again), Ignore my last posting - a quick reboot and your app works fine - sadly mine still does not and I can't fathom why - but at least the problem is with my app and not a general issue! Regards, NicAnonymous
July 20, 2009
The comment has been removedAnonymous
July 21, 2009
Hi Brad, you might wanna have a look at this - while editing if you have a validation error highlighted and you change the selection on the grid it breaks the the binding. And the only remedy thereon would be reload the page/app - a possible solution is to like binding the IsEnabled property of the grid to the IsItemValid property of the form. However, this behaviour is wrong by default, see what we can do about it?Anonymous
July 29, 2009
At first I was able to display my datagrid (without DomainDataServices), but when i tried to use DomainDataServices like you did, it keeps getting back to the Error Page. And so it says, "Page not found: "/Home" Any idea what i might do wrong? Really looking forward to your help, Brad.. thanks a lotAnonymous
July 29, 2009
correction for before i mean DomainDataSource, not DomainDataServices. forgive my typoAnonymous
July 29, 2009
[update] hi brad it's me again.. Never mind my last 2-comments before, sorry i made a pure stupid mistake.. now it works, and again, thanks for sharing your work! :)Anonymous
August 01, 2009
Hi Brad i have problem with my POCO object, i am using LinqtoEntity for quering data, and i am created class ProductsR1 because i want to populate my datagrid and dataform with data from 3 tables (or entities: Products, Products_Category and Vendor ), public class ProductsR1 { public ProductsR1() {} [Key] public int ID { get; set; } public string Name { get; set; } public string Description { get; set; } public decimal Price { get; set; } public string Category { get; set; } public string Vendor { get; set; } } Then i wrote query method: public IQueryable<ProductsR1> GetProductsR1() { var q = from p in Context.Products from pc in Context.Product_Category from v in Context.Vendor select new ProductsR1 { ID = p.ID, Name = p.Name, Description = p.Description, Price = p.Price, Category = pc.Name, Vendor = v.Name }; return q; } Here is code from my Products.xaml.cs: ProductsDomainContext ctx = new ProductsDomainContext(); public Products() { InitializeComponent(); this.Loaded += new RoutedEventHandler(Products_Loaded); } void Products_Loaded(object sender, RoutedEventArgs e) { ProductsDataGrid.ItemsSource = ctx.ProductsR1s; ctx.Load(ctx.GetProductsR1Query); //Here i got error } Can you help me with this problem? Am i doing something wrong? Do i have to change my logic? Is ther other way beside writing custom class?Anonymous
August 02, 2009
Milan - I would guess that would work... Why don't you post a repro on the forums and see if we can help? http://silverlight.net/forums/53.aspxAnonymous
August 02, 2009
Hi Brad, did your "Add New" button really adds up new entry to the database permanently? because i can't even seem to make that happen, even when i tried your running demo application, it doesn't add anything. Any idea how this might work?Anonymous
August 02, 2009
Hi, i am noticed that all demo and samples are some CRUD application that work with single entitiy. I didn't see any sample about quering, inserting, updating and deleting against relational entities. I know that this requare a lot of code to write, and you just want to show to us how easy can be writing business app with silverlight and ria. Can you write a demo about CRUD app that show for example data from three entities, it would be great if it would be posible to use dataform and bind to single datasource that provide data from several entities, and trough that datasource to update and delete related entities, and of course to use validation, paging.Anonymous
August 03, 2009
The comment has been removedAnonymous
August 07, 2009
in myAp.web.g.cs i get error referencing the following [] using System.[Web].Ria.Data; using System.Windows.[Ria].Data; where this error come fromAnonymous
August 11, 2009
Hi Brad, I've got some classes in my Entity Model that use inheritance (e.g. Employee inherits from Person). When I try to add a Domain Service Class, the Employee class is not available to select... The Person class is available though... I would expect the opposite, particularly as the Person class is set as Abstract on the model. Any ideas?Anonymous
August 11, 2009
This is a great article on building business applications. We currently use Silverlight/Prism and Unity and everything else here. I was wondering since I seem to see alot of examples written directly on xaml, any chance of showing it using the MVVM pattern? I can infer alot from the samples with delegate commands to my viewmodel. However I am struggling on how to access the childwindow without the viewmodel knowing about the view and vice versa. I am trying to capture the OK button in the childwindow via viewmodel. Any thoughts would be great!! TIA, AmyAnonymous
August 13, 2009
The comment has been removedAnonymous
August 19, 2009
This might sound like a silly question, but where do I get the DB with table "SuperEmployee"? I've looked everywhere for it. I have Northwind installed - are you creating your own table there? If so, are you just filling it with your own data? For now, I think I am going to just use the Employee table to follow along with the tutorials.Anonymous
August 19, 2009
I am using SqlExpress.. look in the MyApp.Web project and the App_Data directory... there you will see a northwnd.mdf file that has the table in it.Anonymous
August 19, 2009
Doh! I am trying to use Sql Server (not express) - I can't believe I didn't look there for the mdf. Thanks Brad!Anonymous
August 19, 2009
Brad, I'm doing research on RIA for our apps migration to silverlight. Examples like this one and others in your series makes me enthusiastic as there are some awesome features to exploit. However, I've not yet found anything on a particular question I have. Your example is fairly simple (I know for demo purposes) in that it gets all the data in the request from your domain service to your data source. The demo just appears to be limiting the data that is sent over the wire to the client. This is fine, but what if my data that I'd be retrieving would be 1000s of records. In my instance I am not necessarily querying a local data store. To get all the records would take minutes. How can (or is it possible) the domain data source and the pager make use of their current client info, current page and page size, to help the domain service on the server be more efficient in returning records through the webservice? ie is there a way to send the current page number and page size to the domain service call? Thanks! Mike GAnonymous
August 19, 2009
Thanks Mike G– Actually, no, the default way .NET RIA Services works is that it only pulls down the data the client requests. So in this example if you are on page 2, you only get page 2’s data… we do this via a serialized LINQ query. The DomainDataSource builds up a LINQ query for just what the client needs (sorting, paging, filtering, etc) and then asks the server for just that data. So my database could have 10,000 records and I would only ever download a page or so at a time. Hope that helpsAnonymous
August 19, 2009
Brad, Ok, I think I have an understanding if you're using L2SQL or EF where the LINQ query isn't executed/performed until the enumeration happens (from my understanding in memory you're just going to manipulate the actual query, but when the service hands back the results the query is executed and the results returned). How would this happen with POCO? If I need to grab objects during the request to hand back the IQueryable I could either load ALL the data up into a POCO Enumerable which is returned as a IQueryable which then is filtered by the LINQ query (BAD). My thought would be to have some kind of page number to get data for and the number of results desired. I could then feed this into my [App Logic] area and it would perform the loading of the POCO enumeration with only the objects that should be serialized to the clients. The real reason that I ask this is that we've yet to convert the entire app over to EF. We're gathering data from several different types of data stores and use an intermediate object to do business operations in the [App Logic] layer. It is these objects we'd like to work with on the client. Thanks (also thanks for the quick response!) Mike G.Anonymous
August 22, 2009
The comment has been removedAnonymous
August 22, 2009
The comment has been removedAnonymous
August 23, 2009
The comment has been removedAnonymous
August 23, 2009
The comment has been removedAnonymous
August 24, 2009
It's a great example, Thanks a lot Brad !!!Anonymous
August 24, 2009
There are two lls in the word old in "from plain olld CLR objects"Anonymous
August 27, 2009
Please fix your urls for big images a href="file:///C:/Users/brada/AppData/Local/Temp/WindowsLiveWriter-429641856/supfilesD1D2F6D/image%5B61%5D.png" mce_href="file:///C:/Users/brada/AppData/Local/Temp/WindowsLiveWriter-429641856/supfilesD1D2F6D/image[61].png" img style="border: 0px none ; display: inline;" title="image_thumb[29]" alt="image_thumb[29]" src="http://blogs.msdn.com/blogfiles/brada/WindowsLiveWriter/Bus.NETRIAServicesJulyUpdatePart1RichDat_1178B/image_thumb%5B29%5D_d5fac640-3d48-45fd-bb32-e9b8bfb009da.png" mce_src="http://blogs.msdn.com/blogfiles/brada/WindowsLiveWriter/Bus.NETRIAServicesJulyUpdatePart1RichDat_1178B/image_thumb%5B29%5D_d5fac640-3d48-45fd-bb32-e9b8bfb009da.png" width="240" border="0" height="131"Anonymous
August 30, 2009
Hi Brad, for views I have problems with domain service because there are no key. Is there a solution? Error 1 The entity 'MaintexpressSilverlight.Web.rqt_frm_intervention_DT_Liste' does not have a key defined. Entities exposed by DomainService operations must have must have at least one property marked with the KeyAttribute. MaintexpressSilverlightAnonymous
September 04, 2009
Hi Brad: Very nice job. Very nice posts. Still having trouble adding a new object. (Either via new Context or using the DomainDataSource context) I notice several other people commenting on this. Any thoughts? Lots of blog posts i've been sifting through so I'm sorry if there was one somewhere that addresses this.Anonymous
September 16, 2009
After adding the datagrid to the home page and testing by pressing F5, my browser brings up the following url: http://localhost:52878/BusinessApplicationTestPage.aspx, which transitions by itself to the Home page url: http://localhost:52878/BusinessApplicationTestPage.aspx#/Home. Everything appears fine -- the datagrid appears with some rows. However, after a very brief moment (2 seconds) though, the application transitions by itself to the following url and error message page: http://errorpage.comcast.net/?cat=Web&con=dc&safe=on&q=localhost Sorry. We can't find "localhost" There was a problem loading your page. Try retyping the URL in the browser address bar above or, visiting a related link below... Any help would be greatly appreciated!Anonymous
September 16, 2009
Hmm... No, i haven't seen that... does it repro consistently? Does it repro when you are on a differnet machine?Anonymous
September 17, 2009
Brad, thanks for responding. Finally, after surfing the Forums in the Microsoft Silverlight web site, I found a tip that seems to have resolved it. I was able to resolve the issue above by starting Visual Studio as Administrator. P.S. Thanks for the blogs.Anonymous
September 17, 2009
Hey Brad, I've implemented the entire tutorial but for my own database. Everything works fine except the permalink. My xap file is called "InmZen.xap" & my table is called "Job" - with a primary key called "IntRef". Also, the name of my page with all the datagrids on etc. is "Home.xaml" Here is my code: // Executes when the user navigates to this page via permalink protected override void OnNavigatedTo(NavigationEventArgs e) { var qs = NavigationContext.QueryString; if (qs.ContainsKey("IntRef")) { dds.FilterDescriptors.Add( new FilterDescriptor("IntRef", FilterOperator.IsEqualTo, qs["IntRef"])); } } private void dataGrid1_SelectionChanged(object sender, SelectionChangedEventArgs e) { var job = dataGrid1.SelectedItem as Job; if (job != null) { PermalinkTextBox.Text = Application.Current.Host.Source.ToString().Replace("ClientBin/InmZen.xap", "") + "#/Home?IntRef=" + job.Lang; } } When I Paste the permalink into a browser, nothing happens (just loads a blank screen). Would you be able to shed some light on the subject? Kind regards,Anonymous
September 17, 2009
The comment has been removedAnonymous
September 17, 2009
Urgent Note: Bringing up Visual Studio 2008 SP1 as a user (PCAdmin, who is a member of Administrators group), opening a Silverlight Business Application project template. The list of Silverlight XAML Controls appears as: (note: I just noted a few; the list is not complete) Pointer Accordion AreaSeries AutoCompleteBox ... DataField DataForm DataGrid DataPager DatePicker DateTimeAxis DescriptionViewer DockPanel DomainDataSource DomainUpDown DoubleInterpolator ... TransitioningContentControl TreeMap TreeView TreeViewItemCheckBox TwilightBlueTheme ValidationSummary Viewbox VirtualizingStackPanel WhistlerBlueTheme WrapPanel Bringing up Visual Studio 2008 SP1 as Administrator, opening a Silverlight Business Application project template. The list of Silverlight XAML Controls appears as: (note: I just noted a few; the list is not complete) Pointer Accordion (missing) AreaSeries (missing) AutoCompleteBox ... DataField (missing) DataForm (missing) DataGrid DataPager DatePicker DateTimeAxis (missing) DescriptionViewer DockPanel (missing) DomainDataSource (missing) DomainUpDown (missing) DoubleInterpolator (missing) ... TransitioningContentControl (missing) TreeMap (missing) TreeView TreeViewItemCheckBox (missing) TwilightBlueTheme (missing) ValidationSummary Viewbox (missing) VirtualizingStackPanel WhistlerBlueTheme (missing) WrapPanel (missing) Also, when I run as Administrator and I select Add New Item in the web project, I don't see the icons for the following Visual Studio installed templates in the Web category:
- Search Sitemap
- Domain Service Class However, when I run Visual Studio as a regular user, the icons appear.
Anonymous
September 24, 2009
Validation Attribute Causes BreakPoint I typed in 'Mall' for Gender then pressed [Tab] key, the application breaks at MyApp08.Web.g.cs, on the line: this.ValidateProperty("Gender", value); of code, below: [DataMember()] [RegularExpression("^(?:m|M|male|Male|f|F|female|Female)$", ErrorMessage="Gender must be 'Male' or 'Female'")] [StringLength(50)] public string Gender { get { return this._gender; } set { if ((this._gender != value)) { this.ValidateProperty("Gender", value); this.OnGenderChanging(value); this.RaiseDataMemberChanging("Gender"); this._gender = value; this.RaiseDataMemberChanged("Gender"); this.OnGenderChanged(); } } } Annotated metadata file (SuperEmployeeDomainservice.metadata.cs) looked like: [RegularExpression("^(?:m|M|male|Male|f|F|female|Female)$", ErrorMessage="Gender must be 'Male' or 'Female'")] public string Gender; System.ComponentModel.DataAnnotations.ValidationException was unhandled by user code Message="Gender must be 'Male' or 'Female'" StackTrace: at System.ComponentModel.DataAnnotations.Validator.ValidationError.ThrowValidationException() at System.ComponentModel.DataAnnotations.Validator.ValidateProperty(Object value, ValidationContext validationContext) at System.Windows.Ria.Data.Entity.ValidateProperty(String propertyName, Object value) at MyApp08.Web.SuperEmployee.set_Gender(String value) InnerException: Note: the same happens when I enter an Issues number out of the range specified.Anonymous
September 28, 2009
I'm new to Silverlight & RIA Services but looking for the best way to handle the following: The table that contains the data I want in my datagrid has several employee userid fields (for ex - createdBy, updatedBy, requester, etc.). In a database view I can join to an employee table in a separate database to get the employee's full name and other details to display on the grid. However, If I want to have a dataform tied to the grid for editing, I cannot do this because if I use a view in EF it is read-only. It seems all the EF examples I see are based tables with FK relationships, but we have many fields that contain codes that are in lookup tables either within or external to the given database and don't follow the FK relationship model. We join to these "lookup" tables for display purposes but not sure how to incorporate this into EF & Domain Service class.