Welcome to the Xceed Community | Help
Community Search  
More Search Options

Foreign key value assignment

Sort Posts: Previous Next
  •  07-07-2010, 2:12 AM Post no. 27422

    Foreign key value assignment

    I've been trying to code my grid to allow a user to choose a job to assign a list of materials to.

    There is a Material table which is bound to the data grid. It has a foreign key link to the Job table.

    I initially bound the Material.Job field but due to the fact that it has a foreign key constraint underneath in Linq2Sql, whenever the grid tried to update the value it would fire the exception 'ForeignKeyReferenceAlreadyHasValueException'.

    Linq has given me a Job1 field which gives me entity access to set it to an existing Job #. So I've tried creating a ForeignKeyConfiguration for this field, and I can get it to display the jobs I want in the ComboBox but it won't then assign the selected Job to the Material.Job1 property. I'm banging my head against a wall here Confused

    Here are some code snippets that might help illustrate what I having been trying to explain.

    My DataGridCollectionViewSources:

    <DockPanel>
            <DockPanel.Resources>
                <xcdg:DataGridCollectionViewSource x:Key="cvs_materials" Source="{Binding Path=Materials}"
                                                   DefaultCalculateDistinctValues="False"
                                                   AutoCreateDetailDescriptions="True"
                                                   AutoCreateItemProperties="True"
                                                   AutoCreateForeignKeyDescriptions="True">
                </xcdg:DataGridCollectionViewSource>
                    <xcdg:DataGridCollectionViewSource x:Key="cvs_jobs" Source="{Binding Path=Jobs}"
                                                   DefaultCalculateDistinctValues="False"
                                                   AutoCreateDetailDescriptions="True"
                                                   AutoCreateItemProperties="True"
                                                   AutoCreateForeignKeyDescriptions="True">
                </xcdg:DataGridCollectionViewSource>
            </DockPanel.Resources>

     My Page class:

     public partial class ViewNewMaterialsPage : Page
        {
            private X1BCSdb db = new X1BCSdb();
            private IQueryable<Material> materials;
            private IQueryable<Job> jobs;

            public IQueryable<Material> Materials {
                get { return materials; }
                set { if (value != null) materials = value; }
            }

            public IQueryable<Job> Jobs {
                get { return jobs; }
                set { if (value != null) jobs = value; }
            }

            public ViewNewMaterialsPage()
            {
                // All materials that aren't already assigned to a job
                materials = from m in db.Materials
                            where !m.Job.HasValue
                            select m;
                jobs = from Job j in db.Jobs
                       where !(j.Cancelled) // or delivered?
                       select j;
                InitializeComponent();
            }
            
            private void Page_Initialized(object sender, EventArgs e)
            {
                this.DataContext = this;
            }

    My XAML for the two fields of interest:

    <xcdg:DataGridControl ItemsSource="{Binding Source={StaticResource cvs_materials}}" Name="NewMaterialsDataGrid" Loaded="NewMaterialsDataGrid_Loaded"
                                  NavigationBehavior="RowOrCell"
                                  CellEditorDisplayConditions="CellIsCurrent" UpdateSourceTrigger="CellEndingEdit" ReadOnly="False"
                                  AutoCreateColumns="False" AutoCreateDetailConfigurations="False"
                                  AutoCreateForeignKeyConfigurations="True" >
                <xcdg:DataGridControl.Resources>
                    <Style x:Key="{x:Type xcdg:ScrollTip}" TargetType="xcdg:ScrollTip">
                        <Setter Property="HorizontalAlignment" Value="Right" />
                        <Setter Property="VerticalAlignment" Value="Center" />
                    </Style>
                </xcdg:DataGridControl.Resources>
                <xcdg:DataGridControl.View>
                    <xcdg:TableView ShowFixedColumnSplitter="False" UseDefaultHeadersFooters="False" ShowScrollTip="True">
                        <xcdg:TableView.FixedHeaders>
                            <DataTemplate>
                                <xcdg:HierarchicalGroupByControl xcdg:TableView.CanScrollHorizontally="False" />
                            </DataTemplate>
                            <DataTemplate>
                                <xcdg:ColumnManagerRow AllowAutoFilter="False" />
                            </DataTemplate>
                        </xcdg:TableView.FixedHeaders>
                    </xcdg:TableView>
                </xcdg:DataGridControl.View>
                <xcdg:DataGridControl.Columns>
                    <xcdg:Column FieldName="ProwosNo" Title="Prowos #" IsMainColumn="True" ReadOnly="True" />
                    <xcdg:Column FieldName="PickingSlipNo" IsMainColumn="False" Title="Picking Slip #" ReadOnly="True" />
                    <xcdg:Column FieldName="LineNo" Title="Line #" ReadOnly="True" />
                    <xcdg:Column FieldName="OrderNumber" Title="Keyed Order #" ReadOnly="True" />
                    <xcdg:Column FieldName="Job" Title="Job #" ReadOnly="False" >
                        <xcdg:Column.DisplayMemberBindingInfo>
                            <xcdg:DataGridBindingInfo Path="Job">
                                <xcdg:DataGridBindingInfo.ValidationRules>
                                    <local:JobValidationRule ValidationStep="ConvertedProposedValue" />
                                </xcdg:DataGridBindingInfo.ValidationRules>
                            </xcdg:DataGridBindingInfo>
                        </xcdg:Column.DisplayMemberBindingInfo>
                        <xcdg:Column.CellEditor>
                            <xcdg:CellEditor>
                                <xcdg:CellEditor.EditTemplate>
                                    <DataTemplate>
                                        <xcdg:NumericTextBox ValueDataType="{x:Type s:Int32}" Value="{xcdg:CellEditorBinding}" />
                                    </DataTemplate>
                                </xcdg:CellEditor.EditTemplate>
                            </xcdg:CellEditor>
                        </xcdg:Column.CellEditor>
                    </xcdg:Column>
                    <xcdg:Column FieldName="Job1" Title="Job # 2" ReadOnly="False" >
                        <xcdg:Column.ForeignKeyConfiguration>
                            <xcdg:ForeignKeyConfiguration ItemsSource="{Binding Source={StaticResource cvs_jobs}}"
                                                          DisplayMemberPath="JobID" >
                            </xcdg:ForeignKeyConfiguration>
                        </xcdg:Column.ForeignKeyConfiguration>
                    </xcdg:Column>

    At the moment the Job # 2 column shows the ComboBox and lists the valid Jobs, but when I select one it doesn't seem to get assigned to the Job1 field. Do I need to define a CellContentTemplate also?

  •  07-07-2010, 10:09 AM Post no. 27431 in reply to 27422

    Re: Foreign key value assignment

    Hi,

      The exception you are refrencing from Linq to SQL suggests that you are trying to change only the value of the PrimaryKey of the object refrenced by your Material.Job. The way to update the Job on your material is to assign an instance of Job for your Material.Job1 property directly. Linq will ensure to update the JobId field according to the new instance of Job affected on your Material.

    You only miss the ValuePath in your ForeignKeyConfiguration to force the Business object to be the selected item in the ComboBox as the value to push in the DataSource once the editting is completed.

     Here is a snippet that demonstrates how to edit a field generated by Linq to SQL (Employee from EmployeeID):

    <xcdg:DataGridControl.Columns>

       <xcdg:Column FieldName="Employee">      

          <xcdg:Column.CellContentTemplate>

             <DataTemplate>

                <TextBlock Text="{Binding FirstName}"/>

             </DataTemplate>

          </xcdg:Column.CellContentTemplate>      

          <xcdg:Column.ForeignKeyConfiguration>

             <xcdg:ForeignKeyConfiguration ItemsSource="{Binding Source={StaticResource cvs_Employees}}"

                                           ValuePath="."

                                           DisplayMemberPath="FirstName" />

          </xcdg:Column.ForeignKeyConfiguration>      

       </xcdg:Column>

    </xcdg:DataGridControl.Columns>


    Christian Nadeau
    Software Developer
    Xceed Software Inc.
  •  07-07-2010, 10:50 PM Post no. 27441 in reply to 27431

    Re: Foreign key value assignment

    Hi Chris thanks heaps for your tip there.

    I tried as you suggested, it makes sense. But after I select the Job from the combo box I do a quick watch on the Material entity and it does not show that it has been updated - the Job1 entity is still 'null'.

    Does setting ValuePath to "." have this desired effect in version 3.2 ??

  •  07-08-2010, 9:15 AM Post no. 27445 in reply to 27441

    Re: Foreign key value assignment

    Hi,

      I tested the exact same scenario with version 3.2.9356.10060 and it works as expected. The "." means you take the SelectedValue of the ComboBox as value assigned to the edited business object's property.


    Christian Nadeau
    Software Developer
    Xceed Software Inc.
  •  08-20-2010, 3:07 AM Post no. 28025 in reply to 27445

    Re: Foreign key value assignment

    I recently upgraded to 3.7 and still couldn't get this to work easily. I did eventually though but I think not through the ForeignKeyConfiguration property.

    I had to jump through several hoops to get it working. Here is how I did it.

    PARTIAL CollectionViewSource

    <xcdg:DataGridCollectionViewSource
            x:Key="cvs_jobs"
            AutoCreateDetailDescriptions="False"
            AutoCreateForeignKeyDescriptions="True"
            AutoCreateItemProperties="False"
            AutoFilterMode="And"
            DefaultCalculateDistinctValues="False"
            DistinctValuesConstraint="Filtered"
            Source="{Binding Path=Jobs}">
            <xcdg:DataGridCollectionViewSource.ItemProperties>
              <xcdg:DataGridItemProperty
                Name="JobID"
                DataType="{x:Type s:Int32}"
                IsReadOnly="True"
                Title="Job #"
                ValuePath="JobID"/>
              <xcdg:DataGridItemProperty
                Name="QuoteID"
                DataType="{x:Type s:Int32}"
                IsReadOnly="True"
                Title="Quote #"
                ValuePath="Quote"/>
              <xcdg:DataGridItemProperty
                Name="Product"
                CalculateDistinctValues="True"
                DataType="{x:Type local:Product}"
                IsReadOnly="False"
                Title="Product"
                ValuePath="Quote1.Product1"/>
              <xcdg:DataGridItemProperty
                Name="Customer"
                CalculateDistinctValues="True"
                DataType="{x:Type local:Customer}"
                IsReadOnly="False"
                Title="Customer"
                ValuePath="Quote1.Customer1"/>

    PARTIAL DataGridControl

    <xcdg:DataGridControl
          Name="JobDataGrid"
          AutoCreateColumns="True"
          AutoCreateDetailConfigurations="True"
          AutoCreateForeignKeyConfigurations="True"
          CellEditorDisplayConditions="CellIsCurrent"
          ItemsSource="{Binding Source={StaticResource cvs_jobs}}"
          NavigationBehavior="RowOrCell"
          UpdateSourceTrigger="CellEndingEdit">
          <xcdg:DataGridControl.Columns>
            <xcdg:Column FieldName="JobID" IsMainColumn="True"/>
            <xcdg:Column FieldName="QuoteID"/>
            <xcdg:Column FieldName="Product"/>
            <xcdg:Column FieldName="Customer" VisiblePosition="3">
              <xcdg:Column.CellContentTemplate>
                <DataTemplate DataType="{x:Type local:Customer}">
                  <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding CustomerName}"/>
                    <TextBlock Text=" ("/>
                    <TextBlock Text="{Binding AccountCode}"/>
                    <TextBlock Text=")"/>
                  </StackPanel>
                </DataTemplate>
              </xcdg:Column.CellContentTemplate>
             
    <xcdg:Column.ForeignKeyConfiguration>
                <xcdg:ForeignKeyConfiguration DisplayMemberPath="CustomerName" ItemsSource="{Binding Source={StaticResource cvs_customers}}" ValuePath="."/>
              </xcdg:Column.ForeignKeyConfiguration>

              <xcdg:Column.CellEditor>
                <xcdg:CellEditor>
                  <xcdg:CellEditor.EditTemplate>
                    <DataTemplate DataType="{x:Type local:Customer}">
                      <ComboBox
                        DisplayMemberPath="CustomerName"
                        ItemsSource="{Binding Source={StaticResource cvs_customers}}"
                        SelectedItem="{xcdg:CellEditorBinding}"
                        SelectedValue="."
                        SelectedValuePath="."/>
                    </DataTemplate>
                  </xcdg:CellEditor.EditTemplate>
                </xcdg:CellEditor>
              </xcdg:Column.CellEditor>
            </xcdg:Column>

          </xcdg:DataGridControl.Columns>

    And now I simply call LinqDataContext.SubmitChanges and it works! I also have the benefit of the editor selecting the correct line in the combobox when beginning edit (which I have seen posts about). I have left my ForeignKeyConfiguration there but I suspect I could delete it. It seems that ForeignKey detection just doesn't work for Linq2Sql but setting a CellContentTemplate and a clever CellEditor seem to do the trick.

View as RSS news feed in XML
Contact | Site Map | Reviews | Legal Terms of Use | Trademarks | Privacy Statement Copyright 2011 Xceed Software Inc.