views:

3191

answers:

4

Hello,

I'm working on a Silverlight 3 app with RIA Services. I've got the app running but for some reason it's only reading data, not committing changes.

Most of the online examples I've seen use Linq2Entities; we're using Linq2SQL (our data model is pretty good as-is without abstraction.)

Here's a snippet of the Service:

[EnableClientAccess]
public class FooService : LinqToSqlDomainService<FooDataContext>
{
    [RequiresAuthentication()]
    public IQueryable<UserProfile> GetUserProfiles()
    {
        return this.Context.UserProfiles;
    }

    [RequiresAuthentication()]
    public void InsertUserProfile(UserProfile profile)
    {
        this.Context.UserProfiles.InsertOnSubmit(profile);
    }

    [RequiresAuthentication()]
    public void UpdateUserProfile(UserProfile currentProfile)
    {
        this.Context.UserProfiles.Attach(currentProfile, true);
    }

    [RequiresAuthentication()]
    public void DeleteUserProfile(UserProfile profile)
    {
        this.Context.UserProfiles.Attach(profile, profile);
        this.Context.UserProfiles.DeleteOnSubmit(profile);
    }
}

Here's a snippet of the XAML I'm using:

<dataControls:DataForm x:Name="_profileForm" AutoGenerateFields="False" CommandButtonsVisibility="Commit" AutoEdit="True" >
                <dataControls:DataForm.EditTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Vertical">
                            <dataControls:DataField Label="Username">
                                <TextBox Text="{Binding UserName, Mode=TwoWay}" />
                            </dataControls:DataField>

                            <dataControls:DataField Label="First Name">
                                <TextBox Text="{Binding FirstName, Mode=TwoWay}" />
                            </dataControls:DataField>

                            <dataControls:DataField Label="Last Name">
                                <TextBox Text="{Binding LastName, Mode=TwoWay}" />
                            </dataControls:DataField>

                            <dataControls:DataField Label="Password">
                                <PasswordBox Password="{Binding Password, Mode=TwoWay}"/>
                            </dataControls:DataField>

                            <!-- [Snip] -->

                            </dataControls:DataField>
                        </StackPanel>
                    </DataTemplate>
                </dataControls:DataForm.EditTemplate>
            </dataControls:DataForm>

And here's a snippet of the Silverlight page:

public partial class Profile : Page
{
    private FooContext _dataContext;

    public Profile()
    {
        InitializeComponent();
        this._dataContext = new FooContext();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        LoadOperation<UserProfile> loadOperation = this._dataContext.Load<UserProfile>(this._dataContext.GetUserProfilesQuery());
        loadOperation.Completed += new EventHandler(this.LoadOperation_Completed);
    }

    private void LoadOperation_Completed(object sender, EventArgs e)
    {
        // Bind the RIA data to the controls
        LoadOperation<UserProfile> loadOperation = sender as LoadOperation<UserProfile>;
        this._profileForm.EditEnded += new EventHandler<DataFormEditEndedEventArgs>(ProfileForm_EditEnded);
        this._profileForm.ItemsSource = loadOperation.Entities;
        this._profileForm.CurrentIndex = 0;
    }

    private void ProfileForm_EditEnded(object sender, DataFormEditEndedEventArgs e)
    {
        this._dataContext.SubmitChanges();
    }
+1  A: 

Is there an error, does nothing happen when you call SubmitChanges?

Here's what I'd try:

  1. Set breakpoints on the server CRUD methods to make sure they're being called.
  2. Make sure you're not passing NULL for any of the values, as that can cause a new instance to be created rather than an update of the existing entity.
  3. I'd try adding an OnSubmitCompleted event to check for errors. Sample code (from this PDF):

    this._dataContext.SubmitChanges(OnSubmitCompleted, null); 
    
    
    private void OnSubmitCompleted(SubmitOperation so) 
    { 
            if (so.Error != null) 
            { 
                    string message = so.Error.Message; 
                    if (so.EntitiesInError.Any()) 
                    { 
                            message = string.Empty; 
                            Entity entityInError = so.EntitiesInError.First(); 
                            if (entityInError.Conflict != null) 
                            { 
                                    EntityConflict conflict = entityInError.Conflict; 
                                    foreach (EntityConflictMember cm in 
                                                                              conflict.MemberConflicts) 
                                    { 
                                            message += string.Format( 
                                                    "Member '{0}' in conflict: Current: {1}, 
                                                                             Original: {2}, Store: {3}", 
                                                    cm.PropertyName, cm.CurrentValue, 
                                                    cm.OriginalValue, cm.StoreValue); 
                                    } 
                            } 
                            else if (entityInError.ValidationErrors.Any()) 
                            { 
                                    message += "\r\n" + 
                                      entityInError.ValidationErrors.First().Message; 
                            } 
                    } 
                    MessageBox.Show(message, "Submit Failed", MessageBoxButton.OK); 
            } 
    }
    
Jon Galloway
1. I set the breakpoints and it is calling the update method.2. No nulls are being passed (and no new records showing up in the DB.)3. Added that event and so.Error = null.The output on the Silverlight client looks normal; I've even added a DataGrid and it reflects the changes from the dataform.I tested the following on the service just to make sure it wasn't a write issue with the DB and it works:var profile = (from profiles in Context.UserProfiles where profiles.DBPrimaryKey == 1 select profiles).First();profile.LastName = "Changed";Context.SubmitChanges();
Nick Gotch
My current suspect is the UpdateUserProfile() method on the domain service, but I tried multiple variations on it with no change. It is being called though, I've verified that.
Nick Gotch
+2  A: 

Does removing the [RequiresAuthentication] change behavior at all?

Another thing to check might be the config file - specifically the HttpHandler declaration verbs (GET,POST).

(bloody meetup message list - I hit my 3 message limit for the day as a newb) :P

JerKimball
A: 

Thanks everyone for the help! I FINALLY figured out what it took to get this to work. I'm not sure exactly why just yet but this solved the problem. I changed the update method to the following:

[RequiresAuthentication()]
public void UpdateUserProfile(UserProfile currentProfile)
{
    UserProfile originalProfile = this.ChangeSet.GetOriginal(currentProfile);
    this.Context.UserProfiles.Attach(currentProfile, originalProfile);
}

whew. Now to just understand why it was unable to attach the entity before grabbing its original version.

Thanks again everyone, much appreciated!!

Nick Gotch
Maybe related to this? http://blog.davidyack.com/journal/2009/7/21/ria-services-domaindatasourcedata-not-updating.html
James Cadd
Can you please accept your answer so it moves to the top? That'll help the next person that runs into this.
Jon Galloway
I'll accept my own answer as soon as I'm able; apparently StackOverflow requires you to wait 48 hours before accepting your own answer.
Nick Gotch
You can get this kind of problem if there is a mismatch in your dataclasses, in my case I had a char(1) field in the database which was null, but the dataclasses had the field as Nullable false
Martin
A: 

by adding this code you are satisfying the optimistic concurrancy requirement

john mcFetridge