Entity Attribute Value Schema

19 posts, 0 answers
  1. Michael
    Michael avatar
    13 posts
    Member since:
    Mar 2012

    Posted 26 Sep 2012 Link to this post

    Hi,

    I'm building a LightSwitch application that needs to make use of a EAV (Entity Attribute Value) database schema. I'm attempting to use a RADGridView to display the attribtues with their values. Due the nature of an EAV model the datatype for each attribute varies. In the database the values are stored in a values table with a column for each value type, the attribute table keeps a record of the value type (I know this is a horrid database design but it fits the requirements). I've attached a entity diagram of the database schema.

    Getting the data into LightSwitch is pretty trivial, as it adding the RadGridView control (Telerik has provided some nice documents on this). What I need to work out how to do is conditionally bind the value columns. Each attribute will only have a single value, but the datatype for each attribute will be different so I can't apply this to the column as a whole. So what I'm looking for is a GridView with two columns (there will be more but let keep it simply), Attribute Name and Attribute Value. The Attribute Value column must bind to the correct column in the AttributeValues table based on the DataType in the Attributes table.

    Any ideas on how to achieve this?
  2. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 01 Oct 2012 Link to this post

    Hi,

     You could try subscribing for the AutoGeneratingColumn event of the RadGridView. Then based on the DataType in the Attributes table add a column with an appropriate binding.

    Kind regards,
    Didie
    the Telerik team

    Time to cast your vote for Telerik! Tell DevPro Connections and Windows IT Pro why Telerik is your choice. Telerik is nominated in a total of 25 categories.

  3. Michael
    Michael avatar
    13 posts
    Member since:
    Mar 2012

    Posted 28 Oct 2012 Link to this post

    Thanks Didie,

    I used a cell data template selector to achieve the required behaviour. This works; there are a few kink to work out but it's fine for v1. I would love to see an example of subscribing to the AutoGeneratingColumns event in Lightswitch.
  4. Michael
    Michael avatar
    13 posts
    Member since:
    Mar 2012

    Posted 30 Oct 2012 Link to this post

    Below is the XAML I've created. I'm struggling with a few issues.
    1) I create the attribute values in the InitialiseWorkspace method if this is a new entry being created. This works but the grid doesn't show the datatemplate until you enter it; i.e. you click on the value column.
    2) If I uncomment the <telerik:GroupDescriptor ... the application throws an Null Reference error
    3) I'm unable to get the EnumEditTemplate to populate with the values.

    It appears that the grid is created prior to the data work space being initialised. I have a funny feeling that this might be due to the threads; you can't enumerate an entity on the UI thread. I'm beginning to wonder if I shouldn't implement the logic in code (C#) rather than XAML; if nothing else it would be easier to debug.

    Any assistance would be highly appreciated. If you would like me to upload the entire solution (including the DB create scripts) let me know.

    <UserControl x:Class="Amplats.ProcessDiary.Controls.Views.LogSheetAttributeValuesGrid"
        xmlns:local="clr-namespace:Amplats.ProcessDiary.Controls.Views"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
     
        <UserControl.Resources>
            <!-- Cell Data Templates-->
            <DataTemplate x:Key="BoolEditTemplate">
                <CheckBox IsChecked="{Binding BoolValue, Mode=TwoWay}" />
            </DataTemplate>
            <DataTemplate x:Key="FloatEditTemplate">
                <TextBox Text="{Binding FloatValue, Mode=TwoWay}" />
            </DataTemplate>
            <DataTemplate x:Key="FloatDisplayTemplate">
                <TextBlock Text="{Binding FloatValue, Mode=TwoWay}" />
            </DataTemplate>
            <DataTemplate x:Key="IntEditTemplate">
                <TextBox Text="{Binding IntValue, Mode=TwoWay}" />
            </DataTemplate>
            <DataTemplate x:Key="IntDisplayTemplate">
                <TextBlock Text="{Binding IntValue}" />
            </DataTemplate>
            <DataTemplate x:Key="StringEditTemplate">
                <TextBox Text="{Binding StringValue, Mode=TwoWay}" />
            </DataTemplate>
            <DataTemplate x:Key="StringDisplayTemplate">
                <TextBlock Text="{Binding StringValue}" />           
            </DataTemplate>
            <DataTemplate x:Key="DateEditTemplate">
                <telerik:RadDatePicker SelectedValue="{Binding DateValue, Mode=TwoWay}"  />
            </DataTemplate>
            <DataTemplate x:Key="DateTimeEditTemplate">
                <telerik:RadDateTimePicker SelectedValue="{Binding DateTimeValue, Mode=TwoWay}"  />
            </DataTemplate>
            <DataTemplate x:Key="EnumEditTemplate">
                <telerik:RadComboBox DisplayMemberPath="Attribute.EnumSet.Name"  ItemsSource="{Binding Attribute.EnumSet}"
                                     SelectedItem="{Binding Attribute.EnumSet.ID}"/>
            </DataTemplate>
     
            <local:AttributeValuesGridCellTemplateSelector x:Key="InputGridEditTemplate"
                                                BoolTemplate="{StaticResource BoolEditTemplate}"
                                                FloatTemplate="{StaticResource FloatEditTemplate}"
                                                IntTemplate="{StaticResource IntEditTemplate}"
                                                StringTemplate="{StaticResource StringEditTemplate}"
                                                DateTemplate="{StaticResource DateEditTemplate}"
                                                DateTimeTemplate="{StaticResource DateTimeEditTemplate}"
                                                EnumTemplate="{StaticResource EnumEditTemplate}"/>
            <local:AttributeValuesGridCellTemplateSelector x:Key="InputGridDisplayTemplate"                     
                                                BoolTemplate="{StaticResource BoolEditTemplate}"
                                                FloatTemplate="{StaticResource FloatDisplayTemplate}"
                                                IntTemplate="{StaticResource IntDisplayTemplate}"
                                                StringTemplate="{StaticResource StringDisplayTemplate}"
                                                DateTemplate="{StaticResource DateEditTemplate}"
                                                DateTimeTemplate="{StaticResource DateTimeEditTemplate}"
                                                EnumTemplate="{StaticResource EnumEditTemplate}"/>
     
        </UserControl.Resources>
     
        <Grid x:Name="LayoutRoot" Background="White">
            <telerik:RadGridView x:Name="AttributeValuesGrid" ItemsSource="{Binding Screen.AttributeValues, Mode=TwoWay}"
                                 AutoGenerateColumns="False"
                                 ShowColumnFooters="False"
                                 ShowGroupPanel="True"
                                 ColumnWidth="*">
                <telerik:RadGridView.GroupDescriptors>
                    <!--<telerik:GroupDescriptor Member="Display Group" />-->
                </telerik:RadGridView.GroupDescriptors>
                <telerik:RadGridView.Columns>
                    <telerik:GridViewDataColumn Header="Attribute"
                                                Width="150"
                                                DataMemberBinding="{Binding Attribute.Name}"
                                                TabStopMode="Skip"/>
                    <telerik:GridViewDataColumn Header="Description"
                                                Width="250"
                                                TabStopMode="Skip"/>
                    <telerik:GridViewDataColumn Header="Value"
                        CellTemplateSelector="{StaticResource InputGridDisplayTemplate}"
                        CellEditTemplateSelector="{StaticResource InputGridEditTemplate}" />
                    <telerik:GridViewDataColumn Header="Units"
                                                Width="50"
                                                TabStopMode="Skip"/>
                    <telerik:GridViewDataColumn Header="Value Comment"
                                                DataMemberBinding="{Binding Comment}"
                                                Width="*" />
                    <telerik:GridViewDataColumn Header="Display Group"
                                                DataMemberBinding="{Binding Attribute.AttributeDisplayGroup.Name}" />
                    <telerik:GridViewDataColumn Header="Display Group Display Order"
                                                DataMemberBinding="{Binding Attribute.AttributeDisplayGroup.DisplayOrder}"
                                                IsVisible="False"
                                                SortingState="Ascending"/>
                    <telerik:GridViewDataColumn Header="Attribute Display Order"
                                                DataMemberBinding="{Binding Attribute.DisplayOrder}"
                                                IsVisible="False"/>
                </telerik:RadGridView.Columns>
            </telerik:RadGridView>
        </Grid>
    </UserControl>
  5. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 31 Oct 2012 Link to this post

    Hi,

    Regarding your issues:
    1. You say that the grid doesn't show the DataTemplate until you click on the value column. Have you set this DataTemplate as CellEditTemlate? If so, then it will be shown only when the GridViewCell is in edit mode. In that case you should set it as CellTemplate.
    2. I can see that in the GroupDescriptor you have set the Member to be the Header of a Column. This is not correct. You should specify a valid Member (property) of the bound business object. For example for the DataMemberBinding of the "Display Group" column you have used this member: Attribute.AttributeDisplayGroup.Name;
    3. I suppose that you have not bound the RadComboBox inside the DataTemplate properly. Please check this online demo showing DataBinding for RadComboBox and check what is the DataContext for the EnumEditTemplate? Is it the one that you need?

    In case you can still experience the problems, may I ask you if you could reproduce the same problems in a Silverlight application?

    Regards,
    Didie
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  6. Michael
    Michael avatar
    13 posts
    Member since:
    Mar 2012

    Posted 01 Nov 2012 Link to this post

    Hi Didie,

    Thanks for the reply.

    I fixed the issue with the GroupDescriptor; me being stupid.

    Regarding the other two points. I think I've done these "correctly". I have an CellEditTemplateSelector and a CellTemplateSelector. The binding on the combobox look correct (although debugging XAML is a pain in the ...).

    However, I still seeing some odd behaviour which I think is all related. I've uploaded to screenshots:

    • OnOpen.png - This is immediately after I've opened the screen
    • ChangeGroup.png - I simply drag the column into the group by box and remove the previous one (programmatically created one). Please note that I've used the exact same binding for the GroupDescriptor and the column.

    I should mention that I create the data in the grid when the screen is opened in the InitializeDataWorkspace method. It really looks like I'm running into an issue where the data is not fully created when added to the grid. Is there a way to reload the grid after the data is created; this would be an easy test?

  7. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 02 Nov 2012 Link to this post

    Hello,

    What is the result if you place the ComboBox outside the GridView? You could call the Rebind() method in order to reload the GridView. Does it help?

    Regards,
    Didie
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  8. Michael
    Michael avatar
    13 posts
    Member since:
    Mar 2012

    Posted 03 Nov 2012 Link to this post

    Hi Didie,

    Thanks for the quick response. The binding on the combobox is a binding issue; I was binding to the wrong thing. I now get an "It is not valid to execute the operation on the current thread." message; I suspected this anyway.

    I'm still having issues with the templates now working correctly. So I created a simple search screen that you open an existing set of entities; i.e. the entities aren't created programmatically, simple display something from the database. I'm still having issues with the grid not displaying the data until it is force to "refresh" in this case I have a simple button that calls the Rebind method on the grid. I've attached two screenshots showing this; excuse the rather large button (this is only need for testing).

    I have a CellTemplateSelector and a CellEditTemplateSelector defined. I added a break point on the SelectTemplate Method the method doesn't fire when the screen is opened. And only fires when I press the "rebind" button.
  9. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 05 Nov 2012 Link to this post

    Hi,

    This would be a strange behaviour.  May I ask you to perform a simple test and let me know what is the result if you directly set a CellTemplate/CellEditTemplate for the column? What is the result if you set this Screen to be your initial Screen? What is the result if you test the same approach on a simple Silverlight project?

    Greetings,
    Didie
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  10. Michael
    Michael avatar
    13 posts
    Member since:
    Mar 2012

    Posted 08 Nov 2012 Link to this post

    Hi,

    I did the tests:
    • Setting the CellTemplate/CellEditTemplate directly in the column works as expected. The cell rendered correctly and the grouping worked programmatically. I used a check box for the test
    • Making the screen the initial screen did nothing. I get the same result; i.e. I had to call the rebind or enter the cell for editing.

    Regarding the combo box. This is now working; I had the bindings wrong and then due to the lazy load nature of LS I had to call back into the logical thread.

  11. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 09 Nov 2012 Link to this post

    Hi,

    Thank you for the update.
    This would be really strange behaviour. Are you able to reproduce it in a simple demo Silverlight project which we could debug locally? 

    Kind regards,
    Didie
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  12. Michael
    Michael avatar
    13 posts
    Member since:
    Mar 2012

    Posted 09 Nov 2012 Link to this post

    Hi Didie,

    The easiest is that I simply give you the LightSwitch project and the create scripts for the database. The current version of the LS project isn't big nor is there anything really sensitive about it. The SQL scripts will build the database and some test data. Unfortunately, LS projects tend to be a bit bloated so it would be a bit difficult to upload to here; if you send me a link I will upload it. Alternatively, I can upload it to my Skydrive account but I would need your email address.
  13. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 13 Nov 2012 Link to this post

    Hi,

    I have already tested applying a CellTemplateSelector and a CellEditTemplateSelector defined similar to your code snippet in a LightSwitch project and they were applied fine. In my project the TemplateSelectors are defined in the code behind for the same UserControl. 
    Unfortunately I cannot attach the project as it is too big, that is why I am asking you to test the same approach in Silverlight. The result should be the same. Please try this and hopefully you will find the problem with this simple test.

    Greetings,
    Didie
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  14. Michael
    Michael avatar
    13 posts
    Member since:
    Mar 2012

    Posted 17 Nov 2012 Link to this post

    Hi Didie,

    LightSwitch projects are a touch bloated.

    Anyway I've been doing some digging in between my day job. The good news is that I've isolated the problem. The bad news is that I haven't found a descent work around yet. I'm hoping you can help.

    The first problem (selector not firing on load) was cause be me having a groupdescriptor; the groupdescriptor is suffering from the same problem as the template selector.
    There are three entity collections (sets) involved two of which are part of the screen data and the third is related. If you look at the dbschema on my first post the entity sets are the LogSheetEntries, AttributeValues and the Attributes. The first two are part of the screen data the third (Attributes) is not. The Attributes contains the data I need for the selector and the grouping.

    I create the attributevalue entities programmatically when the screen is opened based on some input parameters (below is the code for creating the entities). 
    The problem I'm having is that when the screen is created the value for the related attribute entities are null; I have a check in my selector for null which cause a default template to be returned. Within a small amount of time these value come through, its slow enough that you can visually see it when I bind a column to the AttributeValues.Attribute.DataType. However, because the data come through this is why the rebind works. My gut was right I'm seeing a lazy load issue. To be clear the problem is LightSwitch not the Telerik control which is outstanding.

    I obviously need to find a solution. Any ideas how I can cause the cells to update when LightSwitch bothers to supply the data?

    // populate the attributes
               foreach (Attribute attrib in Attributes)
               {
                   try
                   {
                       AttributeValue attribVal = this.LogSheetEntryProperty.AttributeValues.AddNew();
                       attribVal.Attribute = attrib;
                   }
                   catch (Exception ex)
                   {
                       Trace.TraceError("Error adding attribute to logsheet entry", ex.Message);
                   }
               }
     


  15. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 21 Nov 2012 Link to this post

    Hello,

    Indeed, when you have a grouping applied, then the GridView will load only all the visible groups in a collapsed state. As they are collapsed, there are no rows under the groups, no rows/cells are being created. So it is expected that the SelectTemplate method will not be invoked. I should mention that this is a general logic - only the visual elements that need to be shown, will be realized.

    I am not sure why you need to get this event be initially fired, if you indeed insist on that then you will need to expand the groups so that its child rows to be created. Please keep in mind that realizing those additional visual elements will slow down the performance. 

    Greetings,
    Didie
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  16. Michael
    Michael avatar
    13 posts
    Member since:
    Mar 2012

    Posted 25 Nov 2012 Link to this post

    Hi Didie,

    I think our lines are crossed. The behaviour with the group descriptors and none visible elements is expected and desired. What is not expected is that the related entities are null till a short while after the control has loaded. This unfortunately leads to some issues. The problem is clearly the lazy loading of entities within LightSwitch. What I need is some way to rebind the grid control once the related entities have loaded.
  17. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 26 Nov 2012 Link to this post

    Hi,

    I am not sure that I understand your final goal. What are you going to do after an additional Rebind()? Would it be possible to do the same when the DataLoaded event is raised? If you could be more specific, I would advise you more properly.

    Greetings,
    Didie
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  18. Michael
    Michael avatar
    13 posts
    Member since:
    Mar 2012

    Posted 27 Nov 2012 Link to this post

    Hi Didie,

    I'm must admit I'm not explaining very well. So let me try from scratch.

    I have a LightSwitch screen that consists of two entities, LogSheetEntry and AttributeValues (see attachment). There is a third entity, Attributes, that contains all the "meta-data" for the AttributeValues. The Attributes entity set is not part of the screen data but  I have added it to the Included data on the AttributesValues query.

    The AttributeValues is the data that is using in the grid data binding. The problem I'm having is that on the initial data load event some related Attributes data is null. The two problematic fields are the Attributes.DisplayGroup.Name and the Attributes.DataType.Name; I believe that this is because the attributes are being access via the navigation properties and LightSwitches lazy loading is catching me. As neither of these properties are directly used in any of the bindings no events are fired when the data does update. 
     
    I hope this explains it better.
  19. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 30 Nov 2012 Link to this post

    Hi,

    Thank you for the clarifications.

    In order to diagnose where the problem relies may I ask you to perform those tests:
    1. Test the same with the MS DataGrid or with a ListBox.
    2. What happens if you invoke an additional Rebind() on a button click, or what happens when you sort a column after the data seems to be loaded?
     

    Kind regards,
    Didie
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

Back to Top