实体框架相关表获取和保存数据

Ken*_*Ken 0 c# linq entity-framework relationship winforms

我一直在NETSO中寻找一些答案 - 我对实体框架几乎是一个菜鸟..所以我对相关实体确实有一些困惑..我正在使用 C# , Winforms , Linq , EF6^ (生成的反向数据库类在 DAL 项目中)

我很难解决这个问题。我有 3 个表,它们与第四个表相关 - 第 4 个表使用其他 3 个表中的 PK_ID 列 - 配置为外键,它们还组成了复合键(主键)。

我的粗略 ER 图。

ER图

我需要在 EF 查询中做的是获取多个列以将数据绑定绑定到列表视图。

我想要的列是 EnumerationCode、Part.Number、Part.Description。

我将使用 ProdID (我将 Products 绑定到 DropDown )作为这些附加值的 getter。

所以基本上我想到了这一点 Select From TernaryTable T Join EnumID on ENumTable.EnumID where T.ProdID = myProdID order by EnumCode [Join this to Select Part.Number, Part.Description From PartID = TernaryTable.PartID )

我认为可能有一个简单的解决方案来获取这些数据,然后如何保存对数据的任何更改 - 但正如我所说,我迷失了。

我需要两种方法,一种是获取数据,另一种是保存数据发生的任何更改。

我读过这个

使用 Linq toEntity 从表和相关表中获取记录

实体框架 linq 查询 Include() 多个子实体

但似乎我仍然迷失在多重关系中。

编辑

我认为在 Haralds 出色的答复之后,我需要并且可以发布更好的声明以及真实的图表!

更好的 SQL 图

现在查看表格信息:

我想要 MprnEnum.RefName、Part.PartNumber、Part.Name、Part.Description,其中 ProductID = [Product.ID - 我将提供的此 ID] 按 MPRNENUM.RefName 订购。我希望能够使用 VS EF 从数据库生成的实体类对 ProdPartEnum 执行 CRUD。

有 20 个 RefName,每个产品都有许多 EnumID,并且 EnumID 可以属于许多产品,这些 ProdEnum 中的每一个都有一个关联的部分。许多零件可以属于许多 ProdEnum

典型的表条目可能如下所示: ProdID = 1, EnumID = [1-20] , PartID [1-1000] 其中产品 ID = 1 ,我们有 20 行 EnumID,并且每一行都有一个 PartNumber 。

如果需要,我可以发布更多详细信息。

Har*_*lse 5

天哪,这真是奇怪的多对多对多!

通常情况下会有以下设计:

  • EveryProduct有零个或多个Parts,EveryPart用于零个或多个Products(多对多ProductPart
  • 每个Product都有零个或多个Enumerations,每个Enumeration被零个或多个使用Products(多对多ProductEnumeration
  • EveryPart有零个或多个Enumerations,EveryEnumeration用于零个或多个Parts(多对多EnumerationPart

这将导致三个联结表ProductPart, ProductEnumeration, 和EnumerationPart

您选择了只有一个连接表的设计。

您确实意识到,在您的设计中,一旦 aProduct有 a Part,则 theProduct和 thePart都具有相同的Enumeration,不是吗?除了the 之外,您不能有product更多或其他的a 。你不能有 a和 a但没有。EnumerationsPartsproductProductPartEnumerations

如果您确实想将数据库限制于此,您将拥有如下类:

class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Junction> Junctions { get; set; }
}
class Part
{
    public int Id { get; set; }
    public int Number { get; set; }
    public string Description { get; set; }
    public virtual ICollection<Junction> Junctions { get; set; }
}
class Enumeration
{
    public int Id { get; set; }
    public int Code { get; set; }
    public virtual ICollection<Junction> Junctions { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

你的联结表将是这样的:

public class Junction
{
    // foreign keys; composite primary key
    public int ProductId { get; set; }
    public int EnumId { get; set; }
    public int PartId { get; set; }

    public virtual Product Product { get; set; }
    public virtual Enumeration Enumeration { get; set; }
    public virtual Part Part { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

请注意:在实体框架中,非虚拟属性代表表中的实际列;虚拟属性表示表之间的关系

您的 DbContext 将包含四个表:

class ManyDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Enumeration> Enumerations { get; set; }
    public DbSet<Part> Parts { get; set; }
    public DbSet<Junction> Junctions {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

最后在 OnModelCreating 中,您必须指定您的设计:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    var junctionConfig = modelBuilder.Entity<Junction>();

    // composite primary key:
    junctionConfig.HasKey(junc => new { junc.ProductId, junc.PartId, junc.EnumId);

    // every junctionconfig has a mandatory foreign key to Product in ProductId
    // which represent a one-to-many (one Product has many Junctions)
    junctionConfig.HasRequired<Product>(junc => junc.Product)
        .WithMany(product => product.Junctions)
        .HasForeignKey<int>(junc => junc.ProductId);

    // every junctionconfig has a mandatory foreign key to Enumerations in EnumerationId
    // which represent a one-to-many (one Enumeration has many Junctions)
    junctionConfig.HasRequired<Enumeration>(junc => junc.Enumeration)
        .WithMany(enumeration => enumeration.Junctions)
        .HasForeignKey<int>(junc => junc.EnumId);

    // every junctionconfig has a mandatory foreign key to Pars in PartId
    // which represent a one-to-many (one Part has many Junctions)
    junctionConfig.HasRequired<Part>(junc => junc.Part)
        .WithMany(part => part.Junctions)
        .HasForeignKey<int>(junc => junc.PartId);

    base.OnModelCreating(modelBuilder);
}
Run Code Online (Sandbox Code Playgroud)

回到你的问题

给定 a ,productId给我所有EnumerationCodes, Part.Number,Part.Description记录ProductProductId

当使用实体框架时,人们倾向于在外键上执行联接,而不是使用表中的虚拟属性,这使得事情变得更加复杂。

如果您使用虚拟属性,查询将变得简单且非常直观:

var result = dbContext.Junctions
    .Where(junction => junction.ProductId == productId)
    .Select(junction => new
    {
        EnumerationCode = junction.Enumeration.EnumerationCode,
        PartNumber = junction.Part.Number,
        PartDescription = junction.Part.Description,
    });
Run Code Online (Sandbox Code Playgroud)

实体框架足够智能,可以检测需要哪些连接。

如果您确实想要进行连接,则必须与三个表进行连接。这样的连接看起来很可怕:

var x = dbContext.Junctions                              // from all junctions
    .Where(junction => junction.ProductId == productId)  // take only the ones with productId

                                                          // The first join:
    .Join(dbContext.Parts,                                // Join with Parts
        junction => junction.PartId,                      // from the Junction take the PartId,
        part => part.Id,                                  // from the Parts take the Id
        (junction, part) => new                           // when they match make one new object
        {                                                 // containing some properties
            EnumerationId = junction.EnumId,
            PartNumber = part.Number,
            PartDescription = part.Description,
        })

                                                          // Second Join
        .Join(dbContext.Enumerations,                     // Join with enumerations
            junction => junction.EnumerationId,           // from the 1st join result take EnumerationId
            enumeration => enumeration.Id,                // from enumerations take Id
            (junction, enumeration) => new                // when they match make one new object
            {                                             // containing your desired properties
                EnumerationCode = enumeration.Code,
                PartNumber = junction.PartNumber,
                PartDescription = junction.PartDescription,
            });
Run Code Online (Sandbox Code Playgroud)

您很幸运,您不需要产品的说明。如果您使用虚拟属性,这会很容易:

var result = dbContext.Junctions
    .Where(junction => junction.ProductId == productId)
    .Select(junction => new
    {
        Description = junction.Product.Description,
        EnumerationCode = junction.Enumeration.EnumerationCode,
        PartNumber = junction.Part.Number,
        PartDescription = junction.Part.Description,
    });
Run Code Online (Sandbox Code Playgroud)

由您决定编写四个表的联接。查看差异并决定从现在开始要使用哪种方法。