[英]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建議的另一個很酷的想法。
如前所述,使用具有自動增量或 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.