使用 EF 在 Blazor 中使用 SyncFusion 数据网格显示二维动态表

发布于 2025-01-10 13:05:14 字数 266 浏览 0 评论 0原文

如何展示&使用 EF 数据库连接在 Blazor 中编辑真正动态的 SyncFusion 数据网格表。棘手的部分是二维动态:具有 x 行数和 y 列数(来自其他表)。

在本例中,我有一个包含多个任务(行)和多个角色(列)的动态表,其中可以为每个任务/角色组合为每个角色分配不同的工作量(双数)。

所需的组件是动态 ExpandoObject,包括。能够更新的附加方法(因为字典本质上是只读的)、用于存储数组数据的数据库接口(据我所知 EF 没有提供)以及 razor 页面中的实现。

How to show & edit truly dynamic SyncFusion datagrid table in Blazor with EF database connection. The tricky part is the 2-dimensional dynamic: having x number of rows AND y number of columns (coming from other tables).

In this case, I have a dynamic table with a number of Tasks (rows) and a number of Roles (columns) where each Role can be assigned with different efforts (double number) for each Task/Role combination.

The required components are a dynamic ExpandoObject incl. additional methods to be able to update (because the dictionary by nature is read-only), a database interface to store the array data (which EF does not provide to my knowledge) and the implementation in the razor page.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

↘人皮目录ツ 2025-01-17 13:05:14

这就是我解决它的方法:

  1. 一个动态对象,具有用于读取和读取的相应方法。更新:
public class EffortItem : DynamicObject
{
    public Dictionary EffortDict = new Dictionary();

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        string name = binder.Name;
        return EffortDict.TryGetValue(name, out result);
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        EffortDict[binder.Name] = value;
        return true;
    }

    public override IEnumerable GetDynamicMemberNames()
    {
        return this.EffortDict?.Keys;
    }

    public void Add(string Key, object Value)
    {
        EffortDict.Add(Key, Value);
    }

    public object Get(string Key)
    {
        var ret = (EffortDict.TryGetValue(Key, out object result)) ? result : null;
        return ret;
    }
}
  1. 从数据库加载和存储动态对象数据的数据库接口方法:
//##################################
//### Converter for Efforts data
public async Task> GetDynEfforts()
{
    List dynList = new List();

    try
    {
        //### Get DB data
        var efforts = await this.Efforts.ToListAsync();
        var tasks = await this.PTask.ToListAsync();
        var roles = await this.Roles.ToListAsync();
        int ix = 1; double myEff = 0.0;
        string tName = "";

        if (efforts.Count == 0) return null;

        //### Create dynamic object
        dynList = Enumerable.Range(1, tasks.Count).Select((iy) =>
        {
            ix = 1;
            tName = tasks.Where(t => t.Id == iy).FirstOrDefault().NAME;
            EffortItem dynEff = new EffortItem();
            dynEff.Add("tID", iy);
            dynEff.Add("Task", tName);
            foreach (Role pRole in roles)
            {
                myEff = efforts.First(e => e.PTask == iy && e.Role == ix).eHrs;
                dynEff.Add(pRole.NAME, (double) myEff);
                ix++;
            }
            return dynEff;
        }).Cast().ToList();

        return dynList;

    } catch (Exception args)
    {
        MessagingCenter.Send(new AlertContent("Get Data Error", args.Message + "/" + args.InnerException, "fas fa-exclamation-triangle"), "AlertNotification");
        return null;
    }
}

public async Task SetDynEfforts(EffortItem updEfforts)
{
    //### Get DB data
    Efforts myEffort = null;
    var roles = Roles.ToList();
    double myEff = 0; int tID;

    //### Update db data from dynamic object
    try
    {
        tID = (int)updEfforts.Get("tID");
        foreach (Role pRole in roles)
        {
            var ok = double.TryParse(updEfforts.Get(pRole.NAME).ToString(), out myEff);
            if (!ok) myEff = 0;
            myEffort = Efforts.Where(e => (e.PTask == tID && e.Role == pRole.Id)).FirstOrDefault();

            if (myEffort != null)
            {
                myEffort.eHrs = myEff;
                this.Efforts.Update(myEffort);
            } else
            {
                myEffort = new Efforts
                {
                    PTask = tID,
                    Role = pRole.Id,
                    eHrs = myEff
                };
                this.Efforts.Add(myEffort);
            }

        }

        await this.SaveChangesAsync();
        return true;

    } catch
    {
        return false;
    }
}
  1. Razor 页面以 2 个动态维度和 CRUD 处理事件动态显示表:
@if (dynList == null)
{
Loading...
}
else
{     
    <SfGrid DataSource="@dynList" AllowPaging="false" Toolbar="@ToolbarItems" AllowSorting="true" EnableAltRow="true" AllowGrouping="false" AllowTextWrap="true" Height="500">
        <GridEvents OnActionComplete="EffortsActionHandler" OnActionFailure="ActionFailureHandler" TValue="EffortItem"></GridEvents>
        <GridEditSettings AllowAdding="false" AllowDeleting="false" AllowEditing="true" AllowEditOnDblClick="true"></GridEditSettings>
        <GridColumns>
            @foreach (var colName in dynList[0].GetDynamicMemberNames())
            {
                @switch (colName) { 
                    case "Task":
                        <GridColumn Field="@colName" Width="250" IsPrimaryKey="true" AllowEditing="false" TextAlign="TextAlign.Left"></GridColumn>
                        break;
                    case "tID":
                        break;
                    default:
                    <GridColumn Field="@colName" Width="120" Format="N2" AllowEditing="true" TextAlign="TextAlign.Right">
                    </GridColumn>
                        break;
                    }
             }
        </GridColumns>
    </SfGrid>
    <p></p>
}

@code {
    List dynList { get; set; } = null;
    dynamic propEff = new ExpandoObject();
    List tasks;
    List roles;
    private List ToolbarItems = new List() { "Edit", "Update", "Cancel" };

    protected override async Task OnInitializedAsync()
    {
        tasks = await db.PTask.ToListAsync();
        roles = await db.Roles.ToListAsync();
        int ix = 1;
        string tName = ""; string rName = "";

        //### Get DB values into table object
        dynList = await db.GetDynEfforts();

        //### Create dummy entries if db is empty
        if (dynList == null)
        {
            //### Create new dynamic object
            dynList = new List();

            dynList = Enumerable.Range(1, tasks.Count).Select((iy) =>
            {
                ix = 1;
                tName = tasks.Where(t => t.Id == iy).FirstOrDefault().NAME;
                EffortItem dynEff = new EffortItem();
                dynEff.Add("tID", iy);
                dynEff.Add("Task", tName);
                foreach (Role pRole in roles)
                {
                    dynEff.Add(pRole.NAME, (double)0.0);
                    ix++;
                }
                return dynEff;

            }).Cast().ToList();

            //### Save to db as initial setup
            foreach (EffortItem dynEff in dynList) db.SetDynEfforts(dynEff);
        }
    }

    public async void EffortsActionHandler(ActionEventArgs args)
    {
        if (args.RequestType == Syncfusion.Blazor.Grids.Action.Save)
        {
            //if (!db.SetDynEfforts(args.Data).Result) throw new InvalidOperationException("Error during DB save operation");
            var ret = db.SetDynEfforts(args.Data);
        }
    }

This is how I solved it:

  1. a dynamic object with respective methods to use for read & update:
public class EffortItem : DynamicObject
{
    public Dictionary EffortDict = new Dictionary();

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        string name = binder.Name;
        return EffortDict.TryGetValue(name, out result);
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        EffortDict[binder.Name] = value;
        return true;
    }

    public override IEnumerable GetDynamicMemberNames()
    {
        return this.EffortDict?.Keys;
    }

    public void Add(string Key, object Value)
    {
        EffortDict.Add(Key, Value);
    }

    public object Get(string Key)
    {
        var ret = (EffortDict.TryGetValue(Key, out object result)) ? result : null;
        return ret;
    }
}
  1. Database interface methods to load and store the dynamic object data from/into database:
//##################################
//### Converter for Efforts data
public async Task> GetDynEfforts()
{
    List dynList = new List();

    try
    {
        //### Get DB data
        var efforts = await this.Efforts.ToListAsync();
        var tasks = await this.PTask.ToListAsync();
        var roles = await this.Roles.ToListAsync();
        int ix = 1; double myEff = 0.0;
        string tName = "";

        if (efforts.Count == 0) return null;

        //### Create dynamic object
        dynList = Enumerable.Range(1, tasks.Count).Select((iy) =>
        {
            ix = 1;
            tName = tasks.Where(t => t.Id == iy).FirstOrDefault().NAME;
            EffortItem dynEff = new EffortItem();
            dynEff.Add("tID", iy);
            dynEff.Add("Task", tName);
            foreach (Role pRole in roles)
            {
                myEff = efforts.First(e => e.PTask == iy && e.Role == ix).eHrs;
                dynEff.Add(pRole.NAME, (double) myEff);
                ix++;
            }
            return dynEff;
        }).Cast().ToList();

        return dynList;

    } catch (Exception args)
    {
        MessagingCenter.Send(new AlertContent("Get Data Error", args.Message + "/" + args.InnerException, "fas fa-exclamation-triangle"), "AlertNotification");
        return null;
    }
}

public async Task SetDynEfforts(EffortItem updEfforts)
{
    //### Get DB data
    Efforts myEffort = null;
    var roles = Roles.ToList();
    double myEff = 0; int tID;

    //### Update db data from dynamic object
    try
    {
        tID = (int)updEfforts.Get("tID");
        foreach (Role pRole in roles)
        {
            var ok = double.TryParse(updEfforts.Get(pRole.NAME).ToString(), out myEff);
            if (!ok) myEff = 0;
            myEffort = Efforts.Where(e => (e.PTask == tID && e.Role == pRole.Id)).FirstOrDefault();

            if (myEffort != null)
            {
                myEffort.eHrs = myEff;
                this.Efforts.Update(myEffort);
            } else
            {
                myEffort = new Efforts
                {
                    PTask = tID,
                    Role = pRole.Id,
                    eHrs = myEff
                };
                this.Efforts.Add(myEffort);
            }

        }

        await this.SaveChangesAsync();
        return true;

    } catch
    {
        return false;
    }
}
  1. the Razor page to dynamically show the table in 2 dynamic dimensions and CRUD handling events:
@if (dynList == null)
{
Loading...
}
else
{     
    <SfGrid DataSource="@dynList" AllowPaging="false" Toolbar="@ToolbarItems" AllowSorting="true" EnableAltRow="true" AllowGrouping="false" AllowTextWrap="true" Height="500">
        <GridEvents OnActionComplete="EffortsActionHandler" OnActionFailure="ActionFailureHandler" TValue="EffortItem"></GridEvents>
        <GridEditSettings AllowAdding="false" AllowDeleting="false" AllowEditing="true" AllowEditOnDblClick="true"></GridEditSettings>
        <GridColumns>
            @foreach (var colName in dynList[0].GetDynamicMemberNames())
            {
                @switch (colName) { 
                    case "Task":
                        <GridColumn Field="@colName" Width="250" IsPrimaryKey="true" AllowEditing="false" TextAlign="TextAlign.Left"></GridColumn>
                        break;
                    case "tID":
                        break;
                    default:
                    <GridColumn Field="@colName" Width="120" Format="N2" AllowEditing="true" TextAlign="TextAlign.Right">
                    </GridColumn>
                        break;
                    }
             }
        </GridColumns>
    </SfGrid>
    <p></p>
}

@code {
    List dynList { get; set; } = null;
    dynamic propEff = new ExpandoObject();
    List tasks;
    List roles;
    private List ToolbarItems = new List() { "Edit", "Update", "Cancel" };

    protected override async Task OnInitializedAsync()
    {
        tasks = await db.PTask.ToListAsync();
        roles = await db.Roles.ToListAsync();
        int ix = 1;
        string tName = ""; string rName = "";

        //### Get DB values into table object
        dynList = await db.GetDynEfforts();

        //### Create dummy entries if db is empty
        if (dynList == null)
        {
            //### Create new dynamic object
            dynList = new List();

            dynList = Enumerable.Range(1, tasks.Count).Select((iy) =>
            {
                ix = 1;
                tName = tasks.Where(t => t.Id == iy).FirstOrDefault().NAME;
                EffortItem dynEff = new EffortItem();
                dynEff.Add("tID", iy);
                dynEff.Add("Task", tName);
                foreach (Role pRole in roles)
                {
                    dynEff.Add(pRole.NAME, (double)0.0);
                    ix++;
                }
                return dynEff;

            }).Cast().ToList();

            //### Save to db as initial setup
            foreach (EffortItem dynEff in dynList) db.SetDynEfforts(dynEff);
        }
    }

    public async void EffortsActionHandler(ActionEventArgs args)
    {
        if (args.RequestType == Syncfusion.Blazor.Grids.Action.Save)
        {
            //if (!db.SetDynEfforts(args.Data).Result) throw new InvalidOperationException("Error during DB save operation");
            var ret = db.SetDynEfforts(args.Data);
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文