【问题标题】:C# Entity Framework Generic class -> reload all child entitiesC# Entity Framework 通用类 -> 重新加载所有子实体
【发布时间】:2018-03-29 17:19:53
【问题描述】:

我目前有一个多对多关系层次结构数据库 tblProjects->tblLines->tblGroups->tblStations 等。还有一个实体框架 6 模型。

这些实体框架类都实现了一个基类“tblBase”:

  public abstract class TblBase : INotifyPropertyChanged
{
    private int _id;
    public int ID
    {
        get
        {
            return _id;
        }
        set
        {
            _id = value;
            NotifyPropertyChanged();
        }
    }

    private Nullable<int> _coid;
    public Nullable<int> COID
    {
        get
        {
            NotifyPropertyChanged();
            return _coid;
        }
        set
        {
            _coid = value;
            NotifyPropertyChanged();
        }
    }

    private string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
            NotifyPropertyChanged();
        }
    }

我有一个允许我选择任何节点作为父类型的树视图,目前我有一个方法可以让我重新加载所有子实体。

我想看看如何将其设为通用:

      private async static Task<bool> RefreshLinesAsync(LocalUser ThisUser, ProjectEntities DBContext, object Entity)
    {
        List<object> NonExistingNodes = new List<object>();
        var bContinue = false;
        var PassedEntity = Entity as TblBase;

        //Scan through all DB child entities and reload their DB values
       foreach (var SubEntity in DBContext.tblLines.Where(x => x.ProjectID == PassedEntity.ID).ToList())
        {
            await DBContext.Entry(SubEntity).ReloadAsync().ContinueWith(x =>
            {
                if (!x.IsFaulted)
                {
                    if ((SubEntity.COID.GetValueOrDefault() != 0) && (SubEntity.COID.GetValueOrDefault() != ThisUser.ID))
                        NotifyCOIDConflict(SubEntity, new CheckedOutArgs()
                        {
                            ConflictCOID = SubEntity.COID.GetValueOrDefault()
                        });
                    bContinue = true; 
                }
            }, TaskScheduler.FromCurrentSynchronizationContext());
            if (bContinue)
                //Continue to child entities method
                await RefreshGroupsAsync(ThisUser, DBContext, SubEntity);
        }
        return true;
    }

    private async static Task<bool> RefreshGroupsAsync(LocalUser ThisUser, ProjectEntities DBContext, object Entity)
    {
        List<object> NonExistingNodes = new List<object>();

        var bContinue = false;
        var PassedEntity = Entity as TblBase;

        foreach (var SubEntity in DBContext.tblGroups.Where(x => x.LineID == PassedEntity.ID).ToList())
        {
            await DBContext.Entry(SubEntity).ReloadAsync().ContinueWith(x =>
            {
                if (!x.IsFaulted)
                {
                    if ((SubEntity.COID.GetValueOrDefault() != 0) && (SubEntity.COID.GetValueOrDefault() != ThisUser.ID))
                        NotifyCOIDConflict(SubEntity, new CheckedOutArgs()
                        {
                            ConflictCOID = SubEntity.COID.GetValueOrDefault()
                        });
                    bContinue = true;
                }
            }, TaskScheduler.FromCurrentSynchronizationContext());
            if (bContinue)
                await RefreshStationsAsync(ThisUser,DBContext, SubEntity);
        }
        return true;
    }

我认为唯一有用的方法是 Set(),尽管它不提供 Where() 方法,这很关键,因为我不想检索整个表。

【问题讨论】:

  • dbcontext 中有一个名为 Set() 的方法,它具有 Where() 函数。您可以将它与您的基本类型一起使用:DBContext.Set&lt;TblBase&gt;().Where(...).
  • @Seididieci 我试过了,我得到一个例外,我的 tblBase 不是我的模型的一部分
  • 对不起,我没有注意到你的基类是抽象的......如何让你的函数泛型为private async static Task&lt;bool&gt; RefreshLinesAsync&lt;TEntity&gt;(LocalUser ThisUser, ProjectEntities DBContext, TEntity Entity)
  • @Seididieci 我可以试试,你能大致告诉我这种方法的外观吗?

标签: c# entity-framework-6 generic-programming


【解决方案1】:

您可以使您的函数通用。他们可能喜欢这个:

private async static Task<bool> RefreshLinesAsync<TEntity>(LocalUser ThisUser, ProjectEntities DBContext, TEntity Entity) where TEntity : TblBase
{
    List<TEntity> NonExistingNodes = new List<TEntity>();
    var bContinue = false;
    var PassedEntity = Entity as TblBase;

    foreach (var SubEntity in DBContext.Set<TEntity>().Where(x => (x as TblBase).ProjectID == PassedEntity.ID).ToList()) {
       //Your other code here...
    }
}

函数定义中的where子句,确保该方法只能被TblBase的子类调用。

编辑:

我忘了提到你需要在 foreach 循环中将 SubEntity 转换为 TblBase 才能使用它...

编辑(响应 cmets):

如果您需要从实体中获取所有 TblBase 子类,如果将它们保存在单独的表中,您将无法使您的函数如此通用:当您必须添加更多子类时,它将变得难以维护。

我建议您通过 Table Per Hierarchy 使用单个表(参见 MSDN 中的this 文章)将 TblBase 从抽象类更改为具体类,然后您可以通过这种方式获得所有这些:

 var allSubClassEntities = DBContext.Set<TblBase>();

【讨论】:

  • 我已经实现了,但现在的问题是我的子实体与我的实体的类型相同,我需要它来假设子实体的类型。
  • 另外,表达式只允许我访问 tblBase 属性。 ProjectID 是我的 tblLines 的导航属性。我需要以某种方式指定导航属性。
猜你喜欢
  • 2023-03-29
  • 2016-06-19
  • 2020-02-06
  • 2016-10-10
  • 1970-01-01
  • 2013-06-25
  • 2013-07-21
  • 2018-09-10
相关资源
最近更新 更多