2

私のアプリケーションでは、EntityFramework4.0モデルファーストを使用しています。Productベーステーブルのように継承を実装し、Productから継承するテーブルがいくつかありSpecificProductます。

継承はedmxファイルに表示されます。データベースを最初に設定するには、デザイナを右クリックして[モデルからデータベースを生成]を選択します。これにより、SQL作成スクリプトが生成されます。

SQLデータベースでSpecificProductテーブルにいくつかの変更を加え、モデルをアップグレードしたいとします。明らかにSpecificProduct、edmxファイルからテーブルを削除し、edmxデザイナーを右クリックして、[データベースからモデルを更新]を選択します。これにより、と
の間の継承が失われます。継承の代わりに、私は1対0..1の関係を持っており、の主キーも。の列になっています。 私のコードは利用可能な継承に依存しているため、プロジェクトはもうビルドされないため、これは実際には私が望む方法ではありません。ProductSpecificProductProductSpecificProduct

SpecificProductに挿入された主キー列を削除し、新しい1から0..1の関係を削除し、edmxデザイナーに継承を再度挿入することで、デザイナーファイルでこれを手動で修正できます。
これを自動的に行う方法はありませんか?

それとも、これは単にモデルファーストの試みの制限であり、私は気づいていませんでした(そして、これが本当に制限である場合は、再度選択することはありません)。

4

2 に答える 2

3

EDMXファイルから手動で何も削除しないでください。削除すると、マッピングは失われます。データベース層には継承に関する知識がないため、継承は常に手動でマッピングする必要があります。あなたは常に基本的な関係から始めますが、それを削除して継承に変更する必要があります。

したがって、あなたの場合は、エンティティを削除せずに、データベースから更新を実行してみてください。新しい列は、プロパティとしてエンティティに追加する必要があります。ところで。モデルファーストとデータベースファーストの間でスワッピングはありません。最初のアプローチまたは2番目のアプローチを使用します。それらの組み合わせはサポートされていません。

于 2011-09-06T09:25:39.873 に答える
1

私はこの同じ問題の解決策を求めていました。テキストテンプレートを使用して、継承の変更を適用する非常に効果的な方法を実現することができました。方法は次のとおりです...

データベースを作成する

まず、他の外部キーとは異なる方法で継承を表す外部キー制約に名前を付ける必要があることを除いて、通常どおりデータベースを作成します。

制約に使用する命名規則は、次のような2文字の接頭辞です。

pkPeople           - Primary key constraint
fkPersonAddress    - Foreign key to the Address table
inInstructorPerson - Foreign key representing inheritance
ckPersonAge        - Check constraint

「データ」エンティティモデルを生成する

次に、新しいエンティティデータモデルを作成し、データベースから生成します。このEDMXファイルでは何も変更しないでください。生成されたとおりの状態を維持する必要があります。そうすれば、データベースに大きな変更を加える必要がある場合は、データベースを削除して再作成するだけで済みます。

変更する必要があるのは、edmxファイルのカスタムツールプロパティから「EntityModelCodeGenerator」を削除することだけです。

テキストテンプレートを追加する

次に、新しいテキストテンプレート(.ttファイル)をプロジェクトに追加します。このテキストテンプレートの役割は、前の手順で作成したXMLベースのedmxファイルを調べて、接頭辞「in」で始まるすべての関連付けを探し、必要に応じてXMLを微調整して、関連付けによって参照されるエンティティを次のようにすることです。継承されたオブジェクト。

これを行うための私のコードは次のとおりです。それを機能させるために必要なのは、10行目のベースEDMXファイルのハードコードされたファイル名を変更することだけです。

<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".edmx" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<#
    var edmx = XDocument.Load(this.Host.ResolvePath("MyData.edmx"));
    var edmxns = edmx.Root.Name.Namespace;

    var csdl = edmx.Root.Element(edmxns + "Runtime").Element(edmxns + "ConceptualModels");
    var csdlSchema = csdl.Elements().First();
    var csdlns = csdlSchema.Name.Namespace;
    var modelns = csdlSchema.Attribute("Namespace").Value;
    var InheritiedObjects = new List<InheritedObject>();

    // GET LIST OF INHERITS
    foreach (var a in csdlSchema.Elements(csdlns + "Association").Where(ca => ca.Attribute("Name").Value.StartsWith("in"))) {
        InheritedObject io = new InheritedObject() { ForeignKey = a.Attribute("Name").Value };

        try {
            io.QualifiedParent = a.Elements(csdlns + "End").Single(cae => cae.Attribute("Multiplicity").Value == "1").Attribute("Type").Value;
            io.QualifiedChild = a.Elements(csdlns + "End").Single(cae => cae.Attribute("Multiplicity").Value == "0..1").Attribute("Type").Value;
            InheritiedObjects.Add(io);

        } catch {
            Warning("Foreign key '" + io.ForeignKey + "' doesn't contain parent and child roles with the correct multiplicity.");
        }   
    }

    // SET ABSTRACT OBJECTS
    foreach (var ao in InheritiedObjects.Distinct()) {
        WriteLine("<!-- ABSTRACT: {0} -->", ao.Parent);
        csdlSchema.Elements(csdlns + "EntityType")
            .Single(et => et.Attribute("Name").Value == ao.Parent)
            .SetAttributeValue("Abstract", "true");
    }
    WriteLine("<!-- -->");

    // SET INHERITANCE
    foreach (var io in InheritiedObjects) {

        XElement EntityType = csdlSchema.Elements(csdlns + "EntityType").Single(cet => cet.Attribute("Name").Value == io.Child);
        WriteLine("<!-- INHERITED OBJECT: {0} -->", io.Child);

        // REMOVE THE ASSOCIATION SET
        csdlSchema.Element(csdlns + "EntityContainer")
            .Elements(csdlns + "AssociationSet")
            .Single(cas => cas.Attribute("Association").Value == modelns + "." + io.ForeignKey)
            .Remove();
        WriteLine("<!--     ASSOCIATION SET {0} REMOVED -->", modelns + "." + io.ForeignKey);

        // REMOVE THE ASSOCIATION
        csdlSchema.Elements(csdlns + "Association")
            .Single(ca => ca.Attribute("Name").Value == io.ForeignKey)
            .Remove();
        WriteLine("<!--     ASSOCIATION {0} REMOVED -->", io.ForeignKey);

        // GET THE CHILD ENTITY SET NAME
        io.ChildSet = csdlSchema.Element(csdlns + "EntityContainer")
            .Elements(csdlns + "EntitySet")
            .Single(es => es.Attribute("EntityType").Value == io.QualifiedChild)
            .Attribute("Name").Value;

        // GET THE PARENT ENTITY SET NAME
        io.ParentSet = csdlSchema.Element(csdlns + "EntityContainer")
            .Elements(csdlns + "EntitySet")
            .Single(es => es.Attribute("EntityType").Value == io.QualifiedParent)
            .Attribute("Name").Value;

        // UPDATE ALL ASSOCIATION SETS THAT REFERENCE THE CHILD ENTITY SET
        foreach(var a in csdlSchema.Element(csdlns + "EntityContainer").Elements(csdlns + "AssociationSet")) {
            foreach (var e in a.Elements(csdlns + "End")) {
                if (e.Attribute("EntitySet").Value == io.ChildSet) e.SetAttributeValue("EntitySet", io.ParentSet);
            }
        }           

        // REMOVE THE ENTITY SET
        csdlSchema.Element(csdlns + "EntityContainer")
            .Elements(csdlns + "EntitySet")
            .Single(es => es.Attribute("EntityType").Value == io.QualifiedChild)
            .Remove();
        WriteLine("<!--     ENTITY SET {0} REMOVED -->", io.QualifiedChild);

        // SET BASE TYPE
        EntityType.SetAttributeValue("BaseType", io.QualifiedParent);
        WriteLine("<!--     BASE TYPE SET TO {0} -->", io.QualifiedParent);

        // REMOVE KEY
        EntityType.Element(csdlns + "Key").Remove();
        WriteLine("<!--     KEY REMOVED -->");

        // REMOVE ID PROPERTY
        EntityType.Elements(csdlns + "Property")
            .Where(etp => etp.Attribute("Name").Value == "ID")
            .Remove();
        WriteLine("<!--     ID PROPERTY REMOVED -->");

        // REMOVE NAVIGATION PROPERTIES THAT REFERENCE THE OLD ASSOCIATION
        List<XElement> NavList = new List<XElement>();
        foreach (var np in csdlSchema.Descendants(csdlns + "NavigationProperty")) {
            if (np.Attribute("Relationship").Value == modelns + "." + io.ForeignKey) {
                WriteLine("<!--     REMOVING NAVIGATION PROPERTY {0} FROM {1} -->", np.Attribute("Name").Value, np.Parent.Attribute("Name").Value);
                NavList.Add(np);

            }
        }
        NavList.ForEach(n => n.Remove());

        // REMOVE NAVIGATION PROPERTIES FROM THE PARENT THAT POINTS TO A FOREIGN KEY OF THE CHILD
        foreach (var np in EntityType.Elements(csdlns + "NavigationProperty")) {
            csdlSchema.Elements(csdlns + "EntityType")
                .Single(cet => cet.Attribute("Name").Value == io.Parent)
                .Elements(csdlns + "NavigationProperty")
                .Where(pet => pet.Attribute("Name").Value == np.Attribute("Name").Value)
                .Remove();
        }

        WriteLine("<!-- -->");
    }

    Write(edmx.ToString());



#>
<#+
    public class InheritedObject : IEquatable<InheritedObject> {
        public string ForeignKey { get; set; }
        public string QualifiedParent { get; set; }
        public string QualifiedChild { get; set; }          
        public string Parent { get { return RemoveNamespace(QualifiedParent); } }
        public string Child { get { return RemoveNamespace(QualifiedChild); } }
        public string ParentSet { get; set; }
        public string ChildSet { get; set; }

        private string RemoveNamespace(string expr) {
            if (expr.LastIndexOf(".") > -1) 
                return expr.Substring(expr.LastIndexOf(".") + 1);
            else
                return expr;
        }

        public bool Equals(InheritedObject other) {
            if (Object.ReferenceEquals(other, null)) return false;
            if (Object.ReferenceEquals(this, other)) return true;
            return QualifiedParent.Equals(other.QualifiedParent);
        }

        public override int GetHashCode() {
            return QualifiedParent.GetHashCode();
        }
    }
#>

結果

テキストテンプレートは、新しい.edmxファイルを(テキストテンプレートのサブファイルとして)作成します。これは最終的な.edmxファイルであり、完全に自動生成された外部キー制約の命名方法に基づいて、正しい継承を持つすべてのエンティティが含まれます。

于 2012-07-04T11:39:38.250 に答える