用于更新由实体的多层表示的树结构的设计模式或算法

时间:2019-02-05 19:07:31

标签: c# algorithm entity-framework design-patterns

在某些情况下,我的目标表具有与FK相关的几个“层”。

Root
    |__A
        |__B
            |__C
                |__D

我正在从平面文件导入一些数据,并将结果投影到一组非常相似的POCO对象中。从那里,我需要从这些POCO对象中选择并进入实体。问题是,鉴于每个级别可以是新的或已经存在并且需要更新,因此如何最好地更新实体。

例如,根对象本身可能已经创建,但是不包含A,因此必须先创建A,然后添加其从属对象。

类似地,根可能已经和A一样存在,但不存在依赖的B。 每个级别都有特定的字段,如果它们已经存在,则需要更新。

1 个答案:

答案 0 :(得分:0)

您的数据库

我假设您的层中存在一对多关系:每个根都有零个或多个As,每个A使用外键完全属于一个根。每个A都有零个或多个B,每个B都使用外键等恰好属于一个A。

在实体框架中,您将拥有类似的东西:

class Root
{
    public int Id {get; set;}
    ... // other properties

    // every Root has zero or more As (one-to-many):
    public virtual ICollection<A> As {get; set;}
}
class A
{
    public int Id {get; set;}
    ... // other properties

    // every A belongs to exactly one Root, using foreign key
    public int RootId {get; set;}
    public virtual Root Root {get; set;}

    // every A has zero or more Bs:
    public virtual ICollection<B> Bs {get; set;}
}
 class B
{
    public int Id {get; set;}
    ... // other properties

    // every B belongs to exactly one A, using foreign key
    public int AId {get; set;}
    public virtual A A {get; set;}

    // every B has zero or more Cs:
    public virtual ICollection<C> Cs {get; set;}
}
etc.
  

在实体框架中,表的列由非虚拟属性表示。虚拟属性表示表之间的关系(一对多,多对多)

您的文件

您提到这可能是因为您已经从文件中读取了Root1,然后与其他子项再次读取了Root1。看来您的文件是扁平的:

Root1, A1, B1, ...
Root1, A1, B2, ...
Root1, A2, B3, ...
Root2, A3, B4, ...
Root1, A4, B5, ...

显然,您具有读取文件“行”的功能:

class Line
{
    public Root Root {get; set;}
    public A A {get; set;}
    public B B {get; set;}
    ...
}

IEnumerable<Line> ReadLines(...) {...}

填充数据库

void FillDatabase(IEnumerable<Line> lines)
{
    // convert the lines into a sequence or Roots with their As,
    // with their Bs, with their Cs, ...
    IEnumerable<Root> roots = lines.GroupBy(line => line.Root,
        (root, linesOfThisRoot) => new Root
        {
            Name = root.Name,
            ... other root properties
            As = linesOfThisRoot.GroupBy(line => line.A,
            (a, linesWithRootAndA) => new A
            {
                Name = a.Name,
                ... other a properties
                Bs = linesWithRootAndA.GroupBy(line => line.B,
                     (b, linesWithRootAB) => new B
                     {
                        ... B properties
                        Cs = linesWithRootAB.GroupBy(line => line.C,
                        {
                           etc.
                        })
                        .ToList(),
                    })
                    .ToList(),
               })
               .ToList(),
            })
            .ToList();
        });
    using (var dbContext = new MyDbContext()
    {        
        dbContext.Roots.AddRange(roots.ToList());
        dbContext.SaveChanges();
    }
}