简体   繁体   中英

Modeling nested data structures in Entity Framework

I'm trying out Entity Framework 7 RC1 (every major version, I check back to see if it's worth the hassle), but I'm having some trouble trying to understand how I'm supposed to model certain entities.

As an example I went back to a simple real-world application I have lying around. It was made to manage Windows print servers (ugh).

Here's an example of some of the database tables:

  • PrinterType : A table describing the different types of printers (Printers, plotters and MFPs)
  • PrinterManufacturer : A table describing different manufacturers (Xerox, Canon, Samsung, HP, etc.)
  • PrintServer : A table holding name and description of our print servers
  • PrintServerSupport : A table mapping the Server ID, Type ID and Manufacturer ID to show which specific printers a print server supports.

Here's the 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)
)

Now, turning this into C# POCO entities would apparently amount to something along these lines:

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

Now, image I would want to select all print servers, I would merely have to do the following? (Please keep in mind my EF experience with EF is very limited)

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

However, when debugging, this returns the following rather strange resultset:

结果视图

As you can see, the Manufacturer and Type fields are not populated. Curiously enough, the nested Server fields are...

To make things even more annoying, I'm also receiving JSON payloads with nested data. Here's an example:

[
    {
        "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"
            }
        ]
    }
]

Marshaling and unmarshaling this data is a piece of cake, but what about unmarshaling data, and then updating the database? I always found it to be pretty difficult problem, and I'm curious as to how EF is supposed to help out here.

What is the correct way of both modeling the data and querying it?

I don't think lazy loading is enabled by default in EF 7 when you mark your navigation properties virtual (like in EF6). This is to reduce unnecessary trips to the database.

You can load your related entities by using ThenInclude

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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