簡體   English   中英

在實體中使用沒有主鍵的視圖

[英]Using a view with no primary key with Entity

我剛剛開始將應用程序從原始 ADO.NET 和嵌入式 SQL 轉換為實體的項目。 我遇到了應用程序使用的其中一個視圖的問題。 該視圖沒有主鍵,也沒有唯一標識行的列(或列的組合)。 這是創建視圖的選擇:

SELECT
    filingmonth,
    CEIL(filingmonth / 3),
    licnum,
    filingyear,
    DECODE(GROUPING(insurername), '1', '- All Insured -', insurername),
    insurername,
    policylinecode,
    linedescription,
    SUM(NVL(grosspremium, 0)),
    SUM(DECODE(taxexempt, 1, grosspremium, 0)),
    TRUNC(
      CASE
        WHEN
          (
            b.rsn IS NOT NULL
            OR A.zeroreport = 1
          )
          AND b.datereceived IS NULL
            THEN A.datereceived
        ELSE b.datereceived
      END),
    SUM(aip.iscompanyadmitted(b.naiccocode, b.naicalienid)),
    A.insuredid
  FROM
    aip.slbtransinsured A
  LEFT OUTER JOIN aip.slbtransinsurer b
  ON
    A.insuredid = b.insuredid
  LEFT OUTER JOIN aip.slblinecodes C
  ON
    b.policylinecode = C.linecode
  WHERE
    A.submitted = 1
  AND A.entryincomplete = 0
  GROUP BY
    licnum,
    filingmonth,
    filingyear,
    TRUNC(
      CASE
        WHEN
          (
            b.rsn IS NOT NULL
            OR A.zeroreport = 1
          )
          AND b.datereceived IS NULL
            THEN A.datereceived
        ELSE b.datereceived
      END),
    ROLLUP(insurername, aip.iscompanyadmitted(b.naiccocode, b.naicalienid),
    policylinecode, linedescription), A.insuredid;

以下是一些示例數據,顯示有些行完全重復(第 3 行和第 4 行):

FILINGMONTH CEIL(FILINGMONTH/3) LICNUM FILINGYEAR DECODE(GROUPING(INSURERNAME),'1','-ALLINSURED-',INSURERNAME)                                         INSURERNAME                                                                                          POLICYLINECODE LINEDESCRIPTION                                                                                                                                                                                          SUM(NVL(GROSSPREMIUM,0)) SUM(DECODE(TAXEXEMPT,1,GROSSPREMIUM,0)) TRUNC(CASEWHEN(B.RSNISNOTNULLORA.ZEROREPORT=1)ANDB.DATERECEIVEDISNULLTHENA.DATERECEIVEDELSEB.DATERECEIVEDEND) SUM(AIP.ISCOMPANYADMITTED(B.NAICCOCODE,B.NAICALIENID)) INSUREDID

      6                   2   8150       2007 SAVERS PROPERTY AND CASUALTY INSURANCE CO                                                            SAVERS PROPERTY AND CASUALTY INSURANCE CO                                                            17             OTHER LIABILITY                                                                                                                                                                                                            721.25                                       0 18-JUL-07                                                                                                                                                          0        81 
      6                   2   8150       2007 SAVERS PROPERTY AND CASUALTY INSURANCE CO                                                            SAVERS PROPERTY AND CASUALTY INSURANCE CO                                                            17                                                                                                                                                                                                                                        721.25                                       0 18-JUL-07                                                                                                                                                          0        81 
      6                   2   8150       2007 SAVERS PROPERTY AND CASUALTY INSURANCE CO                                                            SAVERS PROPERTY AND CASUALTY INSURANCE CO                                                                                                                                                                                                                                                                                                      721.25                                       0 18-JUL-07                                                                                                                                                          0        81 
      6                   2   8150       2007 SAVERS PROPERTY AND CASUALTY INSURANCE CO                                                            SAVERS PROPERTY AND CASUALTY INSURANCE CO                                                                                                                                                                                                                                                                                                      721.25                                       0 18-JUL-07                                                                                                                                                          0        81 

insuranceid 是 aip.slbtransinsured 表的 pk,rsn 是 aip.slbtransinsurer 和 aip.slblinecodes 的 pk。

是否有可能在沒有唯一標識符的情況下向實體模型添加視圖? 或者是否有一種簡單的方法可以向視圖添加唯一的行標識符? 視圖只讀取,從不寫入。

是否有可能在沒有唯一標識符的情況下向實體模型添加視圖?

如果沒有主鍵,則沒有。 這將導致這種錯誤

在模型生成期間檢測到一個或多個驗證錯誤:

System.Data.Edm.EdmEntityType:: EntityType 'SalesOnEachCountry' 沒有定義鍵。 定義此 EntityType 的鍵。 System.Data.Edm.EdmEntitySet:EntityType:EntitySet SalesOnEachCountryList 基於類型 SalesOnEachCountry,沒有定義任何鍵。

如果沒有唯一標識符,是的,盡管它具有不合需要的輸出。 具有相同標識符的記錄將引用相同的對象,這稱為身份映射模式

一個例子,即使你的視圖產生這兩行:

Country     Year TotalSales
Philippines 2010 20.000000
Philippines 2011 40.000000

如果您只將主鍵映射到 Country 字段,例如

public class SalesOnEachCountry
{        
    [Key]
    public int CountryId { get; set; }
    public string CountryName { get; set; }        
    public int OrYear { get; set; }
    public long SalesCount { get; set; }
    public decimal TotalSales { get; set; }
}

,即使您的視圖在您的 Oracle 查詢編輯器上生成上述兩行,實體框架也會生成以下錯誤輸出:

Country     Year TotalSales
Philippines 2010 20.000000
Philippines 2010 20.000000

實體框架將認為第二行與第一行是同一對象。

為保證唯一性,您必須確定使每一行唯一的列。 在上面的示例中,必須包含 Year,因此主鍵是唯一的。 IE

public class SalesOnEachCountry
{        
    [Key, Column(Order=0)] public int CountryId { get; set; }
    public string CountryName { get; set; }
    [Key, Column(Order=1)] public int OrYear { get; set; }

    public long SalesCount { get; set; }      
    public decimal TotalSales { get; set; }
}

使您的主鍵類似於上面的屬性,實體框架可以正確地將您的每個視圖的行映射到它們自己的對象。 因此,實體框架現在可以顯示與您的視圖完全相同的行。

Country     Year TotalSales
Philippines 2010 20.000000
Philippines 2011 40.000000

此處的完整詳細信息: http : //www.ienablemuch.com/2011/06/mapping-class-to-database-view-with.html


然后對於沒有任何列來使行唯一的視圖,保證實體框架可以將每個視圖的行映射到它們自己的對象的最簡單方法是為視圖的主鍵創建一個單獨的列,一個很好的候選者就是在每一行上創建一個行號列。 例如

create view RowNumberedView as

select 
    row_number() over(order by <columns of your view sorting>) as RN
    , *
from your_existing_view

然后在您的class RowNumberedView RN 屬性上分配[Key]屬性

擴展 Michael Buen 的答案:我發現使用 ISNULL() 將行號添加到視圖將允許實體框架拉入視圖並自動創建必要的 EntitySet 數據。

create view RowNumberedView as

select 
    ISNULL(ROW_NUMBER() OVER (ORDER BY <column>), 0) AS RN
    , *
from your_existing_view

最近在工作中,我遇到了同樣的問題。 根據我的研究,我找不到關於如何在沒有 PK 的情況下將視圖附加到 EF6 CodeFirst 的任何答案。 大多數似乎涉及遷移,並且非常令人困惑。 我相信 DB first 對工作SQL VIEWS有更好的支持。

我確實嘗試引入一個window function (RowNumber),其想法是使用行標識符作為 PK 來保持 EF6 快樂。 但這使我的查詢總體上更加昂貴,所以我不得不放棄這個想法。

最后,我必須仔細分析我的數據集,看看我是否可以引入一個復合鍵——一個涵蓋我的業務應用程序需要確保工作的所有場景的組合鍵。 請記住也使用IsNull(ColumnName,0)以確保您可以滿足 CodeFirst 流暢方法中的.IsRequired()

IE

HasKey(x => new { x.KfiId, x.ApplicationNumber, x.CustomerId });

我希望這對某人有所幫助 - 我的答案是分析視圖非規范化的數據集並尋找復合鍵。

您可以嘗試Marc Cals建議的另一個很酷的想法。

如果您在 ASP.NET 中使用帶有 MVC 的實體框架

如前所述,使用具有自動增量或 ROW_NUMBER 的列創建視圖。 假設您有該列,它的名稱是rowNumber

轉到 MVC 應用程序的Models目錄中的上下文文件 ( yourDatabaseNameContext ) 文件,找到視圖的定義,而不是

modelBuilder.Entity<yourView>(entity =>
    {
        entity.HasNoKey();

將其更改為:

 modelBuilder.Entity<yourView>(entity =>
            {
                entity.HasKey(e => e.rowNumber);

是否有可能在沒有唯一標識符的情況下向實體模型添加視圖?

可能有一個視圖,其中沒有創建主鍵的單個列或一組列; 因此,你最終會得到虛假的關系。 數據倉庫表有時遵循這種形式。 簡而言之,由於性能原因或報告原因,有時不遵循規范化。

現在到你的第二點:

或者是否有一種簡單的方法可以向視圖添加唯一的行標識符?

我建議您從 slbtransinsured 中選擇所有列,然后查看是否可以找到唯一標識每條記錄的一列。 在我看來,數據應該在 slblinecodes 中有一個代碼類型需要選擇,有點像查找。

對於踢球,嘗試運行它並告訴我你得到了什么:

SELECT filingmonth,
       CEIL (filingmonth / 3),
       licnum,
       filingyear,
       DECODE (GROUPING (insurername), '1', '- All Insured -', insurername),
       insurername,
       policylinecode,
       linedescription,
       SUM (NVL (grosspremium, 0)),
       SUM (DECODE (taxexempt, 1, grosspremium, 0)),
       TRUNC (
           CASE
               WHEN (b.rsn IS NOT NULL OR a.zeroreport = 1)
                    AND b.datereceived IS NULL
               THEN
                   a.datereceived
               ELSE
                   b.datereceived
           END),
       SUM (aip.iscompanyadmitted (b.naiccocode, b.naicalienid)),
       a.insuredid
  FROM aip.slbtransinsured a
       LEFT OUTER JOIN aip.slbtransinsurer b
           ON a.insuredid = b.insuredid
       LEFT OUTER JOIN aip.slblinecodes c
           ON b.policylinecode = c.linecode
 WHERE a.submitted = 1 AND a.entryincomplete = 0
GROUP BY filingmonth,
         licnum,
         filingyear,
         DECODE (GROUPING (insurername), '1', '- All Insured -', insurername),
         insurername,
         policylinecode,
         linedescription,
         TRUNC (
             CASE
                 WHEN (b.rsn IS NOT NULL OR a.zeroreport = 1)
                      AND b.datereceived IS NULL
                 THEN
                     a.datereceived
                 ELSE
                     b.datereceived
             END),
         a.insuredid;

在使用視圖時考慮使用 AsNoTracking()。 這將禁用用於 EF 跟蹤的任何關鍵字段。 然后任何非空字段都可以手動定義為 EF 鍵(即使它重復)。

建議不要創建額外的行計數器字段,因為大多數行計數器最終要求引擎掃描視圖的整個域以生成正確的計數器值,即使使用謂詞(where 子句)進行查詢也是如此。

請參閱鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM