3

ファイル自体を変更せずに EF4 edmx ファイルにいくつかの変更を加えたいと考えています。主に、データベースからモデルを再生成してもすべての変更が失われないようにするためです。私は XSL に精通しており、edmx ファイルと組み合わせて XSL を使用することについて言及されているのを見てきました。これは素晴らしい解決策のように思えますが、実際にこれを設定する方法に関するドキュメントが見つからないようです。edmx ファイルからスタイル シートを参照しますか、それともテンプレートを参照してから何らかの方法で edmx ファイルを読み込むように構成しますか? これに関するリソースは大歓迎です。

説明:

具体的に私がやろうとしているのは、いくつかのビューがモデル内の関係を持つテーブルとして機能するようにモデルを変更することです。ここを参照してください: http://blogs.msdn.com/b/alexj/archive/2009/09/ 01/tip-34-how-to-work-with-updatetable-views.aspx

その方法を使用する際の問題は、データベースを更新してモデルを再生成する必要がある場合、戻ってすべての変更を再度行う必要があることです.xsltを使用してそれらを作成する方法があることを望んでいました.モデルが再生成されたときにビューが削除されないように変更します。

4

3 に答える 3

4

「ここで何を聞かれているのかわかりにくいです」;)

「ファイル自体を変更せずに、EF4 edmx ファイルに変更を加える」とはどういう意味ですか。オリジナルから派生した edmx を作成しますか? その場合、保存時に C# コード (= クラス定義) が自動的に生成されることに注意する必要があります。

私は EF プロジェクトに取り組み、XSLT を使用して edmx ファイルを後処理したり、追加のコードを生成したりしました。これは、ビルド中に手動で、またはバッチ ファイルから呼び出されました。

.Net フレームワークを使用して、単純なPowershell スクリプトから XSLT を呼び出すことができます。EF (3.5) に関する私のブログ投稿は、 edmx 処理を理解するのに役立つかもしれません。

于 2010-08-30T17:57:55.263 に答える
4

これは少し古くなっていると思いますが、最近、保存時に Edmx を変換する解決策を見つけました。これを共有したいと思います。Visual Studio 2012、Entity Framework 6.0、および .Net 4.5 を使用していることに注意してください。Code First は使用していません。

私たちの問題は、Entity Framework を介して生成されたビューに、(必要な列がないのではなく) 不要な主キー列が追加されていたことです。ビューが非決定論的関数を参照していたため、ビューに一意性制約を作成できませんでした。つまり、View キー列を正しく取得する唯一の方法は、edmx ファイルを更新することでした。

これを実現するために、T4 テンプレートを更新して edmx ファイルを読み込み、xslt を使用して翻訳し、再度保存しました。これは、開発者がデザイナー ウィンドウから edmx ファイルを保存するたびに、.cs クラスが生成される前に正しく更新されることを意味します。追加のチェックとして、自動ビルド中に主キーをチェックするための powershell スクリプトも作成しました。

サンプル コードを次に示します (上部の Model1.tt ファイル内)。

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#><#@ output extension=".cs"#>
<#@ assembly name="System.Xml" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Xml.Xsl" #>
<#
XmlDocument rawXDoc = new XmlDocument();
XmlDocument xDoc = new XmlDocument();
XmlReaderSettings settings = new XmlReaderSettings {
    //ConformanceLevel = ConformanceLevel.Document;
    DtdProcessing = DtdProcessing.Prohibit
};
//Note that to use the Host.ResolvePath below you must set hostspecific="true" in the template directive.
using (FileStream rawDocFileSteam =    File.OpenRead(Host.ResolvePath("MyDataModel.edmx"))) {
    using (XmlReader rawDocReader = XmlReader.Create(rawDocFileSteam, settings)) {
        using (XmlTextReader xsltReader = new XmlTextReader(Host.ResolvePath("DataModelTransform.xslt")) ) {
            XslCompiledTransform xsltTransform = new XslCompiledTransform();
            xsltTransform.Load(xsltReader); //Ensure the XML Resolver is null, or a XmlSecureResolver to prevent a Billion Laughs denial of service.
            using (MemoryStream ms = new MemoryStream()) {
                xsltTransform.Transform(rawDocReader, null, ms);
                ms.Position = 0;
                xDoc.Load(ms);
            }
        }
    }
}

xDoc.Save(Host.ResolvePath("MyDataModel.edmx"));

#>

使用する xslt ファイルの例を次に示します。それは2つのことをします。1. ConcurrencyFixed を Transaction_Detail_Base の Version フィールドに追加します。および 2. 無効な主キー列を削除します。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ssdl="http://schemas.microsoft.com/ado/2009/11/edm/ssdl"
                xmlns:edmx="http://schemas.microsoft.com/ado/2009/11/edmx"
                xmlns:edm="http://schemas.microsoft.com/ado/2009/11/edm"
                xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation"
  >
  <xsl:output method="xml" indent="yes"/>

  <!--Ensure blank lines aren't left when we remove invalid PrimaryKey fields.-->
  <xsl:strip-space  elements="*"/>

  <xsl:template match="@*|*|processing-instruction()|comment()">
    <xsl:call-template name="CopyDetails"/>
  </xsl:template>

  <xsl:template name="CopyDetails">
    <xsl:copy>
      <xsl:apply-templates select="@*|*|text()|processing-instruction()|comment()"/>
    </xsl:copy>
  </xsl:template>

  <!--Set concurrency mode to fixed for Transaction_Detail_Base.-->
  <xsl:template match="edmx:ConceptualModels/edm:Schema/edm:EntityType[@Name='Transaction_Detail_Base']/edm:Property[@Name='Version']">
    <xsl:call-template name="AddConcurrencyAttribute"/>
  </xsl:template>

  <!-- Add the ConcurrencyAttribute if it doesn't exist, otherwise update it if it does -->
  <xsl:template name="AddConcurrencyAttribute">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
      <xsl:attribute name="ConcurrencyMode">Fixed</xsl:attribute>
   </xsl:copy>
  </xsl:template>

  <!-- Remove unused primary key columns from views. Should be removed from StorageMode and ConceptualModels -->
  <!--Transaction_Detail. ssdl is the StorageModel section, edm is the ConceptualModel section-->
  <xsl:template match="ssdl:EntityType[@Name='Transaction_Detail']/ssdl:Key/ssdl:PropertyRef | edm:EntityType[@Name='Transaction_Detail']/edm:Key/edm:PropertyRef">
    <xsl:if test="@Name='Asset' or @Name='Date' or @Name='Portfolio' or @Name='System_Reference'">
      <xsl:call-template name="CopyDetails"/>
    </xsl:if>
  </xsl:template>


</xsl:stylesheet>

最後に、ビルド時に .edmx を検証するために使用される Powershell スクリプトの例を次に示します。

function IsValidViewNode([string]$viewName, [string[]]$keyFields, [int]$typeCheck)
{
    [System.Xml.XmlNodeList]$nodelist = $null;
    if ( $typeCheck -eq 1 ) {
        $nodelist = $Xml.SelectNodes("/edmx:Edmx/edmx:Runtime/edmx:StorageModels/ssdl:Schema/ssdl:EntityType[@Name='$viewName']/ssdl:Key/ssdl:PropertyRef", $nsmgr)
    } else
    {
        $nodelist = $Xml.SelectNodes("/edmx:Edmx/edmx:Runtime/edmx:ConceptualModels/edm:Schema/edm:EntityType[@Name='$viewName']/edm:Key/edm:PropertyRef", $nsmgr)
    }
    [int] $matchedItems = 0
    [int] $unmatchedItems = 0
    if ($nodelist -eq $null -or $nodelist.Count -eq 0)
    {
        return $false;
    }
    foreach ($node in $nodelist) {
                $name = ""
                if ($node -ne $null -and $node.Attributes -ne $null -and $node.Attributes -contains "Name" -ne $null )
                {
                    $name = $node.Name
                }
                #Write-Host $name
                if ($keyFields -contains $name) {
                    $matchedItems++
                }
                else {
                    $unmatchedItems++
                }
                #Write-Host $matchedItems
                #Write-Host $unmatchedItems
                #Write-Host $keyFields.Length
            }
    #Right Pad the detail string.,
    $resultString = "Primary Keys for $viewName" + (" " * (50 - "Primary Keys for $viewName".Length))
    if ( $matchedItems -eq $keyFields.Length -and $unmatchedItems -eq 0 ) {
        Write-Host $resultString - Valid
        return ""
    }
    else {
        Write-Host $resultString - INVALID
        return "$viewName,"
    }
}
[string]$PKErrors = ""
# Read the xml file
$xml = [xml](Get-Content 'RALPHDataModel.edmx') 
$nsmgr = new-object Xml.XmlNamespaceManager($Xml.NameTable)
$nsmgr.AddNamespace("edmx", "http://schemas.microsoft.com/ado/2009/11/edmx")
$nsmgr.AddNamespace("ssdl", "http://schemas.microsoft.com/ado/2009/11/edm/ssdl")
$nsmgr.AddNamespace("edm", "http://schemas.microsoft.com/ado/2009/11/edm")
<# 
 ***
 *** VERIFY PRIMARY KEY COLUMNS FOR VIEWS ***
 *** This ensures the developer has run the DataModel.xslt to fix up the .edmx file.
 ***
#>
$PKErrors = $PKErrors + (IsValidViewNode "Transaction_Detail" ("Asset","Date","Portfolio","System_Reference") 1)
$ExitCode = 0
if ($PKErrors -ne "" ) {
    Write-Host "Invalid Primary Keys for Views: " + $PKErrors.TrimEnd(",")
    $ExitCode = 100
}
Exit $ExitCode
于 2014-01-30T23:17:46.467 に答える
0

EF4自体については何も知りませんが、これについてはどうでしょうか。元のedmxファイル(dbから再生成されたもの)が「A.edmx」であるとします。EF4にedmxファイルの名前を付けるときは、URL(許可されている場合)「http://localhost/B.edmx」を付けます。XSLTスタイルシートを使用してA.edmxを変換した結果、このURLに応答する単純なWebサービス(SOAPではなく単純なXMLを意味します)をセットアップします。

または、Webサービスの部分を避け、アプリケーションにB.edmxのタイムスタンプをA.edmxと照合させます。Aが新しい場合、またはBが存在しない場合は、XSLTプロセッサを実行してA.edmxをB.edmxに変換します。

HTH。それでも問題が解決しない場合は、詳細を教えてください。

于 2010-08-30T17:26:49.727 に答える