繁体   English   中英

在实体框架中建模嵌套数据结构

[英]Modeling nested data structures in Entity Framework

我正在尝试Entity Framework 7 RC1(每个主要版本,我都会检查一下是否值得解决),但是在尝试理解如何建模某些实体时遇到了一些麻烦。

作为示例,我回到了一个简单的真实应用程序中。 它用于管理Windows打印服务器(ugh)。

这是一些数据库表的示例:

  • PrinterType :描述不同类型打印机(打印机,绘图仪和MFP)的表
  • PrinterManufacturer :描述不同制造商(施乐,佳能,三星,惠普等)的表格
  • PrintServer :一个表,其中包含我们的打印服务器的名称和描述
  • PrintServerSupport :映射服务器ID,类型ID和制造商ID的表,以显示打印服务器支持哪些特定打印机。

这是DDL:

CREATE TABLE dbo.PrintServer
(
    ID          INT IDENTITY NOT NULL,
    Name        VARCHAR(MAX) NOT NULL,
    Description VARCHAR(MAX) NULL,
    CONSTRAINT [PK_PrintServer_ID] PRIMARY KEY (ID),
)

CREATE TABLE dbo.PrintServerSupport
(
    ID              INT IDENTITY NOT NULL,
    ServerID        INT NOT NULL,
    TypeID          INT NOT NULL,
    ManufacturerID  INT NOT NULL,
    CONSTRAINT [PK_PrintServerSupport_ID] PRIMARY KEY (ID),
    CONSTRAINT [FK_PrintServerSupport_ServerID] FOREIGN KEY (ServerID) REFERENCES PrintServer (ID) ON DELETE CASCADE,
    CONSTRAINT [FK_PrintServerSupport_TypeID] FOREIGN KEY (TypeID) REFERENCES PrinterType (ID) ON DELETE CASCADE,
    CONSTRAINT [FK_PrintServerSupport_ManufacturerID] FOREIGN KEY (ManufacturerID) REFERENCES PrinterManufacturer (ID) ON DELETE CASCADE
)

CREATE TABLE dbo.PrinterType
(
    ID          INT IDENTITY NOT NULL,
    Type        VARCHAR(MAX) NOT NULL,
    CONSTRAINT [PK_PrinterType_ID] PRIMARY KEY (ID),
)

CREATE TABLE dbo.PrinterManufacturer
(
    ID              INT IDENTITY NOT NULL,
    Manufacturer    VARCHAR(MAX) NOT NULL,
    CONSTRAINT [PK_PrinterManufacturer_ID] PRIMARY KEY (ID)
)

现在,将其转换为C#POCO实体显然符合以下几条原则:

public partial class PrinterManufacturer
{
    public PrinterManufacturer()
    {
        PrintServerSupport = new HashSet<PrintServerSupport>();
    }

    public int ID { get; set; }
    public string Manufacturer { get; set; }

    public virtual ICollection<PrintServerSupport> PrintServerSupport { get; set; }
}

public partial class PrinterType
{
    public PrinterType()
    {
        PrintServerSupport = new HashSet<PrintServerSupport>();
    }

    public int ID { get; set; }
    public string Type { get; set; }

    public virtual ICollection<PrintServerSupport> PrintServerSupport { get; set; }
}

public partial class PrintServer
{
    public PrintServer()
    {
        PrintServerSupport = new HashSet<PrintServerSupport>();
    }

    public int ID { get; set; }
    public string Description { get; set; }
    public string Name { get; set; }

    public virtual ICollection<PrintServerSupport> PrintServerSupport { get; set; }
}

public partial class PrintServerSupport
{
    public int ID { get; set; }
    public int ManufacturerID { get; set; }
    public int ServerID { get; set; }
    public int TypeID { get; set; }

    public virtual PrinterManufacturer Manufacturer { get; set; }
    public virtual PrintServer Server { get; set; }
    public virtual PrinterType Type { get; set; }
}

现在,图像我想选择所有打印服务器,我只需要执行以下操作? (请记住,我在EF方面的EF经验非常有限)

using (var db = new DbContext())
{
   var query = db.PrintServer.Include(s => s.PrintServerSupport);
}

但是,在调试时,这将返回以下相当奇怪的结果集:

结果视图

如您所见,“制造商”和“类型”字段未填充。 奇怪的是,嵌套的服务器字段是...

为了使事情更加烦人,我还收到了带有嵌套数据的JSON有效负载。 这是一个例子:

[
    {
        "Name":"REDACTED",
        "Description":"Xerox MFP TEST",
        "SupportedPrinters": [
            {
                "Type":"Printer",
                "Manufacturer":"XEROX"
            },
            {
                "Type":"Plotter",
                "Manufacturer":"XEROX"
            },
            {
                "Type":"MFP",
                "Manufacturer":"XEROX"
            }
        ]
    },
    {
        "Name":"REDACTED-2",
        "Description":"Xerox MFP TEST 2",
        "SupportedPrinters": [
            {
                "Type":"Printer",
                "Manufacturer":"SAMSUNG"
            },
            {
                "Type":"Plotter",
                "Manufacturer":"SAMSUNG"
            }
        ]
    }
]

对数据进行封送和拆封是一件容易的事,但是对数据进行封送再更新数据库又如何呢? 我总是发现这是一个非常困难的问题,并且我对EF应该如何在这里提供帮助感到好奇。

数据建模和查询的正确方法是什么?

我不认为在将导航属性标记为virtual (例如在EF6中)默认情况下在EF 7中启用了延迟加载。 这是为了减少不必要的数据库旅行。

您可以使用ThenInclude加载相关实体

using (var db = new DbContext())
{
   var query = db.PrintServer.Include(s => s.PrintServerSupport)
                             .ThenInclude(p => p.Manufacturer);
}

暂无
暂无

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

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