2012-07-06 8 views
14

私は、アプリケーションを未加工のADO.NETと埋め込みSQLからEntityに変換するプロジェクトを開始しました。アプリケーションで使用されているビューの1つで問題が発生しました。ビューには主キーがなく、行を一意に識別する列(または列の組み合わせ)はありません。エンティティを持つ主キーのないビューを使用

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 

insuredidがあるが、ここでビューを使用して作成された選択でありますpk aip.slbtransinsuredテーブルの場合、rsnはaip.slbtransinsurerとaip.slblinecodesのpkです。

Entityモデルに一意の識別子を付けずにビューを追加することは可能ですか?または、ビューに一意の行識別子を追加する簡単な方法はありますか?ビューは読み込まれず、書き込まれません。

答えて

23

はそれが 一意識別子せずにエンティティモデルにビューを追加することで、すべてのことは可能ですか?

プライマリキーなしの場合、いいえ。それはerrorのこの種になります:

つまたは複数の検証エラーがモデルの生成中に検出されました:

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 

:同じ識別子を持つレコードがあなたのビューは、これら2つの行を生成した場合でも、これはIdentity Map Pattern

例と呼ばれ、同じオブジェクトを参照します例えば

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のクエリエディタで上記の2つの行を生成し、Entity Frameworkのは、この誤った出力を生成します。

Country  Year TotalSales 
Philippines 2010 20.000000 
Philippines 2010 20.000000 

Entity Frameworkの2行目は、最初と同じオブジェクトであることをそれを取るでしょう行。

一意性を保証するには、各行を一意にする列を特定する必要があります。上記の例では、主キーが一意であるようにYearをインクルードする必要があります。すなわち

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

上記の属性と同様の主キーを作成することで、Entity Frameworkは各ビューの行をそれぞれのオブジェクトに正しくマップできます。したがって、Entity Frameworkはビューにある行とまったく同じ行を表示できるようになりました。 http://www.ienablemuch.com/2011/06/mapping-class-to-database-view-with.html


その後の行を一意にするために、任意の列を持っていないあなたの意見については、Entity Frameworkのを保証する最も簡単な方法は、あなたのビューの列のそれぞれをマッピングすることができます:ここ

完全な詳細は

Country  Year TotalSales 
Philippines 2010 20.000000 
Philippines 2011 40.000000 
ビューの 主キーの個別の列を作成することです。各行に行番号列を作成するだけです。例えば

create view RowNumberedView as 

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

次に行カウンタフィールドは、キーとして使用するビューに追加することができるあなたのclass RowNumberedView

+0

ありがとうございます - あなたは本当に私を助けました。私は見た目の一意のID列を持たず、LINQが同じ行を返すために絶望し始めていたOracleテーブルで作業しています。私はEntityクラスで独自のキーを作成することについての提案に従っており、完全に機能します。 – markp3rry

+1

私は投影にGUIDを追加する方が効率的だと思います。バイナリデータフィールドのビューでは、私はover(order by )クエリが遅いことがわかりました。このアプローチに問題はありますか?たとえば、SELECT NEWID()AS PrimaryKey、 FROMビュー –

+0

データベース初回のEntity Frameworkを使用する場合は、「読み取り専用エンティティ」として追加されたビューを主キーに設定する方法があります。ビューを追加すると、[きちんとしたエラー](http://stackoverflow.com/questions/24792259/error-6002-the-table-view-does-not-have-a-primary-key-defined)も表示されますあなたのエンティティがキーなしの読み取り専用エンティティであることを強制する**という明らかなキーはありません。確かにこれを自分で複製する方法がありますか? – ruffin

0

エンティティモデルに一意の識別子を付けずにビューを追加することは可能ですか?

プライマリキーを作成する列が1つもない場合でも、ビューが存在する可能性があります。したがって、あなたは偽の関係に終わる。データウェアハウステーブルは、その形式に従うことがあります。一言で言えば、パフォーマンス上の理由または報告理由のために、正規化が行われないことがあります。

またはビューに一意の行識別子を追加する簡単な方法があります:あなたの第二の点に今

私がお勧めするのは、すべての列をslbtransinsuredから選択し、各レコードを一意に識別する列があるかどうかを確認することです。データは、あなたが選択する必要のあるslblinecodeのコードタイプでなければならず、検索のようなものです。

キックに関しては、これを実行してみて、あなたが得るものを教えてください:

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; 
+0

ありがとう、それはGROUP BY節のGROUPING機能が好きではありません。 slbtransinsuredの唯一の一意の列は、主キーinsuredidで、ビューに複製されます。 slbtransinsuredとslblinecodesの間には関係がありません。slbtransinsurerとslblinecodesの間にのみあります。 –

0

のRN特性に[Key]属性を割り当てます。

linkを参照してください。

12

マイケルBuenからの回答を拡大: ISNULL()でビューに行番号を追加すると、エンティティフレームワークがビューをプルして必要なEntitySetデータを自動的に作成できるようになりました。

create view RowNumberedView as 

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

これは私の仕事ではない、私はすでにrow_numberを入れても、私はまだEntitySetのビューを取得せずに – csuazo

関連する問題