简体   繁体   English

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

[英]Entity Framework Related Tables Get and Save Data

I have been searching the NET and SO for some answers - I am pretty much a noob to Entity framework .. so I do have some confusion on related entities .. I am using C# , Winforms, Linq , EF6^ (Generated Reverse DB classes in a DAL project) 我一直在NETSO中寻找一些答案-我对Entity Framework几乎是个菜鸟..所以我对相关实体确实有些困惑..我正在使用C#,Winforms,Linq,EF6 ^(生成的反向DB类在DAL项目中)

I am having trouble getting my head around this problem. 我无法解决这个问题。 I have 3 tables that are related by a fourth table - the 4th table uses the PK_ID columns from the other 3 Tables - configured as foreign Keys and they also make up the Composite Key (Primary Key). 我有3个与第4个表相关的表-第4个表使用其他3个表中的PK_ID列-配置为外键,它们还构成了复合键(主键)。

My Crude ER Diagram from paint. 我的原始ER图来自油漆。

ER图

What I need to do in a EF Query is to get multiple columns for data binding bind to a listview. 我在EF查询中需要做的是获取多个数据绑定列绑定到列表视图。

The Columns I would like to have are EnumerationCode, Part.Number, Part.Description. 我想要的列是EnumerationCode,Part.Number,Part.Description。

I would be using ProdID (I have Products bound to DropDown ) as the getter for these additional values. 我将使用ProdID(我将Products绑定到DropDown)作为这些附加值的获取器。

So basically I have this in mind 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 Parts where PartID = TernaryTable.PartID ) 因此,基本上,我要牢记这一点:从TernaryTable中选择T在ENumTable.EnumID上加入EnumID,其中T.ProdID = myProdID,按EnumCode顺序[从中选择Part.Number,Part.Description从PartID = TernaryTable.PartID的部件中选择)

I think there is probably a simple solution for how to get this data and then how to save any changes to the data - but as I said I am lost. 我认为对于如何获取此数据然后如何保存对数据的任何更改,可能有一个简单的解决方案-但正如我所说的,我很迷惑。

I need 2 methods , 1 to get the data, and the other to save any changes that occur to the data. 我需要两种方法,一种用于获取数据,另一种用于保存对数据进行的任何更改。

I have read this 我读过了

Get records from table and related related table using Linq to entity 使用Linq到实体从表和相关表中获取记录

Entity framework linq query Include() multiple children entities 实体框架linq查询Include()多个子实体

but seems I am still lost on the multiple relationship. 但似乎我仍然对多重关系迷失了。

EDIT 编辑

I think after Haralds Excellent reply I need and can post a better statement and also a real diagram! 我认为在Haralds出色的答复之后,我需要并且可以发布更好的声明以及真实的图表!

更好的SQL图

And now for table information : 现在获取表信息:

I would like to have MprnEnum.RefName, Part.PartNumber, Part.Name, Part.Description Where ProductID = [Product.ID - this ID I would provide] Ordered By MPRNENUM.RefName. 我想要MprnEnum.RefName,Part.PartNumber,Part.Name,Part.Description,其中ProductID = [Product.ID-我将提供的此ID]由MPRNENUM.RefName排序。 I would like to be able to perform CRUD on the ProdPartEnum using my entity classes generated by VS EF from DB. 我希望能够使用VS EF从数据库生成的实体类对ProdPartEnum执行CRUD。

There are 20 RefNames, Each Product has many EnumID's and EnumIDs can belong to many Products, each of these ProdEnums has one part associated. 有20个RefName,每个产品都有许多EnumID,并且EnumID可以属于许多产品,每个ProdEnum具有一个关联的部分。 Many parts can belong to many ProdEnums 许多零件可以属于许多ProdEnums

A typical table entry might look like this: ProdID = 1, EnumID = [1-20] , PartID [1-1000] Where product ID = 1 , we have 20 rows of EnumID's and each of those Rows would have one PartNumber . 一个典型的表条目可能如下所示:ProdID = 1,EnumID = [1-20],PartID [1-1000]其中产品ID = 1,我们有20行EnumID,每行将有一个PartNumber。

I can post more details if need be. 如果需要,我可以发布更多详细信息。

My, this is a strange many-to-many-to-many! 我的,这是一个奇怪的多对多对多!

Normally one would have the following design: 通常情况下,设计如下:

  • Every Product has zero or more Parts , Every Part is used in zero or more Products (many-to-many ProductPart ) 每个Product具有零个或多个Parts ,每个Part用于零个或多个Products (多对多ProductPart
  • Every Product has zero or more Enumerations , Every Enumeration is used by zero or more Products (many-to-many ProductEnumeration ) 每个Product都有零个或多个Enumerations ,每个Enumeration由零个或多个Products (多对多ProductEnumeration
  • Every Part has zero or more Enumerations , Every Enumeration is used in zero or more Parts (many-to-many EnumerationPart ) 每个Part都有零个或多个Enumerations ,每个Enumeration用于零个或多个Parts (多对多EnumerationPart

This would lead to three junction tables ProductPart , ProductEnumeration , and EnumerationPart 这将导致三个联结表ProductPartProductEnumerationEnumerationPart

You chose for a design with only one junction table. 您选择的设计只有一个连接表。

You do realize that in your design, that as soon as a Product has a Part , that the Product and the Part both have the same Enumeration , don't you? 您确实意识到,在您的设计中,只要一个Product具有PartProductPart都具有相同的Enumeration ,不是吗? You can't have a product with more or other Enumerations than the Parts of the product . product Enumerations数或其他Enumerations不能超过productParts数。 You can't have a Product with a Part but without Enumerations . 你不能有一个Product具有Part但不Enumerations

If you really want to limit your database to this, you'll have classes like this: 如果您真的想将数据库限制在此范围内,则可以使用以下类:

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; }
}

Your junction table will be like: 您的联结表将如下所示:

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; }
}

Be aware: In entity framework the non-virtual properties represent the actual columns in your tables; 请注意:在实体框架中,非虚拟属性表示表中的实际列。 the virtual properties represent the relations between the tables 虚拟属性表示表之间的关系

Your DbContext will have your four tables: 您的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;}
}

Finally in OnModelCreating you'll have to specify your design: 最后,在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);
}

Back to your question 回到您的问题

Given a productId , give me all EnumerationCodes , Part.Number , Part.Description records for the Product with this ProductId 给定一个productId ,请给我具有该ProductIdProduct所有EnumerationCodesPart.NumberPart.Description记录

When using entity framework, people tend to perform joins on foreign keys, instead of using virtual properties in the tables, making things more complicated then needed. 当使用实体框架时,人们倾向于对外键执行联接,而不是在表中使用虚拟属性,这会使事情变得更加复杂。

If you'd use the virtual properties the query would be easy and very intuitive: 如果您使用虚拟属性,则查询将非常简单且直观:

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

Entity Framework is smart enough to detect which joins are needed. 实体框架足够智能,可以检测到需要哪些联接。

If you really want to do the join you'll have to do a join with three tables. 如果您确实想进行联接,则必须对三个表进行联接。 Such a join looks horrific: 这样的连接看起来很可怕:

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,
            });

You are lucky you don't want the product's Description. 您很幸运,不需要产品的说明。 If you'd use the virtual properties this would be easy: 如果要使用虚拟属性,这将很容易:

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,
    });

Up to you to write a join with four tables. 由您来编写一个包含四个表的联接。 See the difference and decide which method you want to use from now on. 查看区别并确定从现在开始要使用哪种方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM