Dynamic Generic Grid with Foreign Columns

Hi Support,

I'm trying to build a 'one size fits most' solution for my EF Core entities in my database.  I'm creating a Blazor Server project so my DbContext is available locally and I'm using a custom data adaptor.  

I've tried a few different ways to construct this grid and I do have it rendering at the moment with the following code:

```

                <SfGrid @ref="SfGrid" ID="Grid" TValue="TValue" AllowPaging="true" AllowResizing="true" AllowSorting="true" ShowColumnChooser="true" Query="@GridQuery"
                    Toolbar="@(new List<string>() { "Add", "Delete", "Cancel", "CsvExport", "ColumnChooser" })"  >
                    <GridFilterSettings Type=Syncfusion.Blazor.Grids.FilterType.Excel></GridFilterSettings>
                    <GridEditSettings AllowAdding="true" AllowEditing="true" AllowDeleting="true" AllowEditOnDblClick="true" />
                    @* <GridEvents TValue="TValue" OnToolbarClick="ToolbarClick" OnActionBegin="ActionHandler" /> *@
                    <GridColumns>
                        @Columns
                    </GridColumns>
                    <SfDataManager Adaptor="Adaptors.CustomAdaptor">
                        <TaurisDataAdaptor TValue="TValue" />
                    </SfDataManager>
                    <GridPageSettings PageSize="@PageSize" PageSizes="true" />
                </SfGrid>

```

I'm using reflection to find out the foreign key types and it builds the grid out.  
```

    void InitializeColumns()
    {
        _columns = builder =>
        {
            int index = 0;
            foreach (var property in ColumnProps.Properties)
            {
                if (!property.Value.IsForeignKey)
                {
                    builder.OpenComponent<GridColumn>(index++);
                    builder.AddAttribute(index++, "Field", property.Key);
                    builder.AddAttribute(index++, "HeaderText", property.Key);
                    if (property.Value.IsPrimaryKey)
                    {
                        builder.AddAttribute(index++, "IsPrimaryKey", true);
                    }
                    builder.CloseComponent();
                    continue;
                }

                // Get the generic type definition of your custom column class
                var gridForeignColumnType = typeof(GridForeignColumn<>);
                Type foreignColumnEntityType = ForeignKeyProps.Where(x => x.ForeignKeyProperty.Equals(property.Key)).First().RelatedEntityType;
                // Make the generic type with the foreign key type
                var constructedForeignColumnType = gridForeignColumnType.MakeGenericType(foreignColumnEntityType);


                Type taurisDataAdaptorType = typeof(TaurisDataAdaptor<>);
                var constructedTaurisDataAdaptorType = taurisDataAdaptorType.MakeGenericType(foreignColumnEntityType);

                builder.OpenComponent(index++, constructedForeignColumnType);
                builder.AddAttribute(index++, "Field", property.Key);
                builder.AddAttribute(index++, "HeaderText", property.Key);
                builder.AddAttribute(index++, "ForeignKeyValue", "Name");
                builder.AddAttribute(index++, "ForeignKeyField", "Id");

                builder.AddAttribute(index++, "ChildContent", new RenderFragment(inner =>
                {
                    inner.OpenComponent<SfDataManager>(index++);
                    inner.AddAttribute(index++, "Adaptor", Adaptors.CustomAdaptor);
                    inner.AddAttribute(index++,"ChildContent", new RenderFragment(innerDm =>
                    {
                        innerDm.OpenComponent(index++, constructedTaurisDataAdaptorType);
                        innerDm.CloseComponent();
                    }));
                    inner.CloseComponent();
                }));
                builder.CloseComponent();
               
            }
        };
    }


```

The issue I'm having is the grid seems to be calling my custom data adaptor for the Foreign key column in what seems to be every single row of data.  It's incessant and eventually crashes as it runs out of connections.  I do not experience this when I define the columns in the component with a concrete object.  

Currently I'm reverting to hard coding my grids but I was wondering if there was an elegant solution to this.


Thanks,

Joe




3 Replies 1 reply marked as answer

MS Monisha Saravanan Syncfusion Team January 23, 2024 11:57 AM UTC


Hi Joseph,


Greetings from Syncfusion.


Before proceeding further with your requirement kindly share us the below details from your end.


  1. Share us the entire Grid code snippet.
  2. Share us whether the reported issue is due to using reflections or while using SfDataManager at your end.
  3. Kindly try the same by utilizing the datasource property of the foreignkey column and revert us if you faced the same issue at your end.
  4. Share us the video demonstration of the reported issue. Are you facing any browser console exception.
  5. If possible share us an simple issue reproduceable sample.


The above requested details will be very helpful for us to validate the reported issue at our end.


Regards,

Monisha



JM Joseph Murray January 23, 2024 03:19 PM UTC

Thank you for your quick response. I got it working properly.  Instead of using the builder for creating the foreign column field with reflection, I created a separate component class that takes the Foreign Entity as the TValue:

```

@using Syncfusion.Blazor.Data
@using Tauris.Pages.Components


@typeparam TForeign where TForeign : class

<GridForeignColumn TValue="TForeign" Field="@Field" HeaderText="@HeaderText" ForeignKeyValue="@ForeignKeyValue" ForeignKeyField="@ForeignKeyField">
    <SfDataManager Adaptor="Adaptors.CustomAdaptor">
        <TaurisDataAdaptor TValue="TForeign" />
    </SfDataManager>
</GridForeignColumn>


@code
{
    [Parameter] public string Field {get;set;}
    [Parameter] public string HeaderText {get;set;}
    [Parameter] public string ForeignKeyValue {get;set;} = "Name";
    [Parameter] public string ForeignKeyField {get;set;} = "Id";

}

```

Then back in the builder code where I initialize the columns:

```

    void InitializeColumns()
    {
        _columns = builder =>
        {
            int index = 0;
            foreach (var property in ColumnProps.Properties)
            {
                if (!property.Value.IsForeignKey)
                {
                    builder.OpenComponent<GridColumn>(index++);
                    builder.AddAttribute(index++, "Field", property.Key);
                    builder.AddAttribute(index++, "HeaderText", property.Key);
                    if (property.Value.IsPrimaryKey)
                    {
                        builder.AddAttribute(index++, "IsPrimaryKey", true);
                    }
                    builder.CloseComponent();
                    continue;
                }

                // Get the generic type definition of your custom column class
               
                Type foreignColumnEntityType = ForeignKeyProps.Where(x => x.ForeignKeyProperty.Equals(property.Key)).First().RelatedEntityType;
                // Make the generic type with the foreign key type
               
                var gridForeignColumnType = typeof(TaurisGridForeignColumn<>).MakeGenericType(foreignColumnEntityType);


                builder.OpenComponent(index++, gridForeignColumnType);
                builder.AddAttribute(index++, "Field", property.Key);
                builder.AddAttribute(index++, "HeaderText", property.Key);
                builder.CloseComponent();
               
            }
        };
    }

```

With that simple change, my DataAdaptor is now running only a couple of times at load.  


Thanks for providing us with a great component set for Blazor!


Marked as answer

MS Monisha Saravanan Syncfusion Team January 24, 2024 01:06 PM UTC

Hi,


Welcome. We are glad to hear that the reported issue has been resolved at your end. Kindly get back to us if you have further queries. As always we will be happy to assist you.





Loader.
Up arrow icon