主頁 > .NET開發 > 第一次查詢相關資料,結果重復資料

第一次查詢相關資料,結果重復資料

2022-05-09 19:38:55 .NET開發

我正在嘗試執行一個查詢,我必須從資料庫中提取資訊,如下所示

找到包含的inventory數字1assets

但是我在我的assets物件中得到了重復的結果,我不明白為什么。

詢問:

[HttpGet("Search/")]
public async Task<ActionResult<DtoInventory>> SearhInventory()
{
    Inventory queryset = await context.Inventories.Include(i => i.Assets).FirstOrDefaultAsync(i => i.inventory_id == 1);
    DtoInventory dto = mapper.Map<DtoInventory>(queryset);
    return dto;
}

資料庫背景關系

using API.Models;
using Microsoft.EntityFrameworkCore;

namespace API.Data
{
    public class ApplicationDbContext : DbContext
    {
        public ApplicationDbContext(DbContextOptions options) : base(options)
        {
        }
        public DbSet<Requirement> Requirements { get; set; }
        public DbSet<Inventory> Inventories { get; set; }
        public DbSet<Asset> Assets { get; set; }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            #region Inventory
            // Table name
            modelBuilder.Entity<Inventory>().ToTable("Inventories");
            // PK
            modelBuilder.Entity<Inventory>().HasKey(i => i.inventory_id);
            #endregion


            #region Asset
            // Table Name
            modelBuilder.Entity<Asset>().ToTable("Assets");
            // PK
            modelBuilder.Entity<Asset>().HasKey(i => i.asset_id);
            // Code
            modelBuilder.Entity<Asset>().Property(a => a.code)
                .HasColumnType("int");

            // Relationship
            modelBuilder.Entity<Asset>()
                .HasOne(i => i.Inventory)
                .WithMany(a => a.Assets)
                .HasForeignKey(a => a.inventory_id); //FK
            #endregion
        }
    }
}

庫存模型

namespace API.Models
{
    public class Inventory
    {
        public int inventory_id { get; set; }
        public string name { get; set; }
        public string location { get; set; }
        public int status { get; set; }
        public DateTime? created_date { get; set; }
        public List<Asset> Assets { get; set; }

    }
}

DtoInventory

namespace API.Dtos
{
    public class DtoInventory
    {
        public int inventory_id { get; set; }
        public string name { get; set; }
        public string location { get; set; }
        public bool status { get; set; }
        public DateTime created_date { get; set; }
        public List<Asset> Assets { get; set; }
    }
}

預期結果:

{
    "inventory_id": 1,
    "name": "cellphones",
    "location": "usa",
    "status": true,
    "created_date": "0001-01-01T00:00:00",
    "assets": 
    [
      {
        "asset_id": 1,
        "code": 1,
        "name": "iphone x",
        "inventory_id": 1
      },
      {
        "asset_id": 2,
        "code": 2,
        "name": "samsung pro",
        "inventory_id": 1
      },
      {
        "asset_id": 3,
        "code": 3,
        "name": "alcatel ",
        "inventory_id": 1
      }
    ]
}

得到的結果:


{
    "inventory_id": 1,
    "name": "cellphones",
    "location": "usa",
    "status": true,
    "created_date": "0001-01-01T00:00:00",
    "assets": [
      {
        "asset_id": 1,
        "code": 1,
        "name": "iphone x",
        "inventory_id": 1,
        "inventory": {
          "inventory_id": 1,
          "name": "cellphones",
          "location": "usa",
          "status": 1,
          "created_date": null,
          "assets": [
            null,
            {
              "asset_id": 2,
              "code": 2,
              "name": "samsung pro",
              "inventory_id": 1,
              "inventory": null
            },
            {
              "asset_id": 3,
              "code": 3,
              "name": "alcatel ",
              "inventory_id": 1,
              "inventory": null
            }
          ]
        }
      },
      {
        "asset_id": 2,
        "code": 2,
        "name": "samsung pro",
        "inventory_id": 1,
        "inventory": {
          "inventory_id": 1,
          "name": "cellphones",
          "location": "usa",
          "status": 1,
          "created_date": null,
          "assets": [
            {
              "asset_id": 1,
              "code": 1,
              "name": "iphone x",
              "inventory_id": 1,
              "inventory": null
            },
            null,
            {
              "asset_id": 3,
              "code": 3,
              "name": "alcatel ",
              "inventory_id": 1,
              "inventory": null
            }
          ]
        }
      },
      {
        "asset_id": 3,
        "code": 3,
        "name": "alcatel ",
        "inventory_id": 1,
        "inventory": {
          "inventory_id": 1,
          "name": "cellphones",
          "location": "usa",
          "status": 1,
          "created_date": null,
          "assets": [
            {
              "asset_id": 1,
              "code": 1,
              "name": "iphone x",
              "inventory_id": 1,
              "inventory": null
            },
            {
              "asset_id": 2,
              "code": 2,
              "name": "samsung pro",
              "inventory_id": 1,
              "inventory": null
            },
            null
          ]
        }
      }
    ]
  }

uj5u.com熱心網友回復:

您將需要另一個 Dto DtoAssetfor EntityAsset

namespace API.Dtos
{
    public class DtoInventory
    {
        public int inventory_id { get; set; }
        public string name { get; set; }
        public string location { get; set; }
        public bool status { get; set; }
        public DateTime created_date { get; set; }

        // List of Dto Assets
        public List<DtoAsset> Assets { get; set; }
    }

    public class DtoAsset
    {
        public int asset_id { get; set; }
        public int code { get; set; }
        public string name { get; set; }
        public int inventory_id { get; set;}
    }
}

uj5u.com熱心網友回復:

所以你有一張桌子Inventories和一張桌子AssetsInventory 和 Assets 之間存在直接的一對多關系:每個 Inventory 都有零個或多個 Assets,每個 Asset 恰好屬于一個 Inventory,即外鍵所指的 Inventory。

間奏曲:還有改進的空間

您決定將資料庫中的行與您與用戶(= 軟體,而不是操作員)的通信方式分開。因此,您有單獨的課程InventoryInventoryDto. 這種分離可能是件好事。如果您預計資料庫布局會發生變化,那么您的用戶不必更改。但是,由于 Inventory 和 InventoryDto 之間的差異非常小,我不確定在這種情況下這種分離是否是一種增強。

  • 如果 status 真的是一個布林值,為什么不將它作為布林值保存在資料庫中呢?此外,狀態是一個令人困惑的名稱。真實狀態是什么意思?
  • InInventory.CreatedDate可以為空。InventoryDto.CreatedDate不是。你為什么要做出這樣的改變?如果資料庫中的 CreatedDate 為空,您將遇到麻煩。您希望 InventoryDto 中的值是多少?

此外,您決定偏離物體框架命名約定當然你可以自由地這樣做,但是這種偏差使你不得不做更多的編程,就像你在OnModelCreating.

如果您遵循約定,您的 Inventory 和 Asses 類將如下所示:

public class Inventory
{
    public int Id { get; set; }
    public string name { get; set; }
    public string location { get; set; }
    public int status { get; set; }
    public DateTime? created_date { get; set; }

    // Every Inventory has zero or more Assets (one-to-many)
    public virtual ICollection<Asset> Assets { get; set; }
}

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

    // Every Asses belongs to exactly one Inventory, using foreign key
    public int InventoryId {get; set;}
    public virtual Inventory Inventory {get; set;}
}

主要區別在于,我使用ICollection<Asset>, 而不是 List。對你Inventory.Asset[4]有明確的意義嗎?你會使用 Asset 是一個事實List嗎?如果你使用ICollection,用戶不能使用索引,這很好,因為你不能保證什么物件會有什么索引。此外,這更重要:您不會強制物體框架將獲取的資料復制到串列中。如果物體框架決定將資料以另一種格式放置會更有效,為什么要強制它使用它作為串列呢?

所以在一對多和多對多中始終堅持ICollection<...>這個界面具有您需要的所有功能:您可以從庫存中添加和洗掉資產,您可以Count在庫存中,您可以一一列舉它們. 您需要的所有功能。

在物體框架中,表中的列由非虛擬屬性表示。虛擬屬性表示表之間的關系(一對多,多對多,...)

外鍵是表中的列,因此它們是非虛擬的。每個資產恰好屬于一個庫存這一事實是表之間的關系,因此該屬性是虛擬的。

回到你的問題

找到包含資產的庫存編號 1。

如果您遵循約定,查詢將很容易:

int inventoryId = 1;
using (var dbContext = new WhareHouseDbContext(...))
{
    Inventory fetchedInventory = dbContext.Inventories
        .Where(inventory => inventory.Id == inventoryId)
        .Select(inventory => new
        {
            // select only the properties that you actually plan to use
            Name = inventory.Name,
            Location = inventory.Location,
            ...

            // The Assets of this Inventory
            Assets = inventory.Assets
                .Where (asset => ...)     // only if you don't want all Assets of this Inventory
                .Select(asset => new
                {
                    // again, only the properties that you plan to use
                    ...

                    // not needed, you already now the value:
                    // InventoryId = asset.InventoryId,
                })
                .ToList(),
      })

      // expect at utmost one Inventory
      .FirstOrDefault();          

      if (fetchedInventory != null)
      {
          ... // process the fetched data
      }
}

Entity framework 知道 Inventories 和 Assets 之間的一對多關系,并且會為你做正確的 (Group-)Join。

資料庫管理系統經過優化,可以組合表格和選擇資料。較慢的部分之一是將所選資料從 DBMS 傳輸到本地行程。

除此之外,您不想傳輸無論如何都不會使用的資料,或者您已經知道其值的資料,例如外鍵,還有另一個原因是不獲取完整物件,也不使用 Include。

每個DbContext都有一個ChangeTrackerwhich 用于檢測如果您呼叫必須更新哪些值SaveChanges每當您獲取一個完整的物件(表中的行)時,該物件都會被放入 ChangeTracker 以及一個副本中。您得到對副本(或原件,沒關系)的參考。如果您對現有的參考進行更改,則副本會更改。

當您呼叫 SaveChanges 時,ChangeTracker 中的原件將按值與副本進行比較。僅更新更改。

如果您在不使用的情況下獲取大量資料Select,則所有這些專案以及它們的副本都會放入 ChangeTracker 中。一旦呼叫 SaveChanges,所有這些獲取的資料都必須與它們的原始資料進行比較,以檢查是否有更改。如果您不將不想更新的專案放入 ChangeTracker 中,這將極大地提升性能。

在物體框架中始終使用Select,并僅選擇您實際計劃使用的屬性。僅獲取完整的行,僅Include在您計劃更新獲取的資料時使用。

匿名型別與具體型別

在我的解決方案中,我使用了匿名型別,這讓我可以自由地選擇我計劃以我想要的格式使用的屬性(可為空或不可為空的 CreatedDate,狀態為布林值或 int)。

缺點是匿名型別只能在定義它的方法中使用。如果您確實需要在方法之外使用資料,例如在回傳值中使用它,請調整Select

.Select(inventory => new InventoryDto
{
    Id = inventory.Id,
    Name = inventory.Name,
    ...

    Assets = inventory.Assets.Select(asset => new AssetDto
    {
        Id = asset.Id,
        ...
    })
    .ToList(),
}

現在你可以在你的方法之外使用這個物件。

自己做組加入

有些人不想使用virtual ICollection<...>,或者他們使用不支持此的物體框架版本。在這種情況下,您必須自己執行 (Group-)Join

var fetchedInventories = dbContext.Inventories
    .Where(inventory => ...)

    // GroupJoin the Inventories with the Assets:
    .GroupJoin(dbContext.Assets,

    inventory => inventory.Id,    // from every inventory take the primary key
    asset => asset.InventoryId,   // from every asset take the foreign key

    // parameter resultSelector:
    // from every inventory, each with its zero or more Assets make one new
    (inventory, assetsOfThisInventory) => new
    {
        Id = inventory.Id,
        Name = inventory.Name,
        ...

        Assets = assetsOfThisInventory.Select(asset => new
        {
            Id = asset.Id,
            ...
        })
        .ToList(),
});

當然,如果需要,請使用具體型別而不是匿名型別。

在一對多關系中,GroupJoin如果您需要獲取“專案,每個專案都有零個或多個子專案”,請使用并從“一側”開始。如果您需要獲取“專案,每個專案都有一個父專案”,我們Join并從“多方面”開始。

因此,使用 GroupJoin 來獲取學校和他們的學生、客戶和他們的訂單、圖書館和他們的書籍,在你的情況下,庫存和他們的資產。

使用 Join 來獲取學生、每個學生與他就讀的學校、訂單以及下訂單的客戶的資料或資產,以及該資產所屬的唯一庫存。

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/471247.html

標籤:C# 林克 实体框架核心 asp.net-web-api2

上一篇:如何使用LINQ按多個欄位分組和排序

下一篇:如何將單一型別的類屬性轉換為該型別的串列

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more