2010-09-17 57 views
6

bearbeiten - Frage Aufräumen um besser auf die aktuelle Ausgabe zu reflektieren:SQLMetal mehrere Fremdschlüssel zeigt auf eine Tabelle Ausgabe

I SQLMetal bin mit Datenbankklassen aus unserem SQL Server db zu generieren. Kürzlich musste ich eine Tabelle hinzufügen, in der mehrere Fremdschlüssel auf dieselbe Tabelle verweisen. Mit LINQPad mit den neuen Tabellen zu spielen, um, ich war in der Lage Eigenschaften zugreifen zu den beiden Fremdschlüssel wie folgt:

  • record.FK_AId
  • record.FK_BId
  • record.FKA
  • record.FKB

... was ist, wie ich es erwarten würde. Das Problem ist, erzeugt die Klassen von SQLMetal erzeugen diese Eigenschaften:

  • record.FK_AId
  • record.FK_BId
  • record.FKA
  • record.FKBTableNameGoesHere

Jetzt ich konnte nur die generierten Klassen so FKBTableNameGoesHere wäre FK_B, aber die generierten Dateien werden sehr oft von verschiedenen Teammitgliedern geändert, so dass ein riesiger Pai wäre n. Gibt es eine einfache Lösung dafür?

Vielen Dank im Voraus.

Edit 2 So, dachte ich, die Lösung nur sein würde, eine partielle Klasse zu erstellen, die eine Eigenschaft hatte genannt, was ich es, sein wollte und die Getter/Setter verweisen auf die schlecht benannte Eigenschaft lassen. Das funktionierte für die Auswahl, aber nicht für where-Klauseln und ähnliches. Jemanden hat eine Lösung ??

Antwort

4

Meine Lösung bestand also darin, einfach eine weitere Teilklasse hinzuzufügen und eine Eigenschaft hinzuzufügen, wobei get/set auf die merkwürdig benannte Eigenschaft FKBTableNameGoesHere verweist. Auf diese Weise müssen wir die generierten Klassen nicht weiter verändern. Nicht genau das Problem zu lösen, aber es sollte den Entwicklern klar machen, was das Eigentum bedeutet. Wer sieht mögliche Probleme mit dieser Lösung?

Bearbeiten - Also, das funktioniert anscheinend nur für die Auswahl von Daten und nicht Filterung darauf basiert. Nicht so einfach wie ich gehofft hatte. Hat jemand andere Vorschläge?

Edit 2 - Jeeze, dachte, das wäre ein etwas allgemeines Problem, aber ich denke nicht. Wie auch immer, es stellte sich heraus, dass ich damit richtig lag. Ich fand diesen Beitrag:

Multiple foreign keys to the same table

Was mich auf die Idee brachte, die ich für eine andere Eigenschaft nicht nur auf die Getter/Setter direkt in Verbindung bringen könnte, da es wahrscheinlich viel mehr als das hinter den Kulissen. Diese Jungs Lösung war nicht genau die Antwort, aber es schickte mich in die richtige Richtung.Das Hinzufügen der Verband Attribut ist, was es schließlich tat

public partial class ProblemClass 
{ 
    [Association(Name = "FK__SomeLinkHere", Storage = "_OriginalPoorlyNamedStorageVariable", ThisKey = "FK_1_Id", OtherKey = "Id", IsForeignKey = true)] 
    public FKType MyNewBetterName 
    { 
     get 
     { 
      return this._OriginalPoorlyNamedStorageVariable.Entity; 
     } 

     set 
     { 
      this.OriginalPoorlyNamedStorageVariable = value; 
     } 
    } 
} 

Going the Bounty offen für jedermann zu verlassen, die noch mit einer saubereren Lösung kommen können.

+0

kann tatsächlich einen Schritt weiter und verwendet _OriginalPoorlyNamedStorageVariable kann vollständig verzichtet werden. Ich bin mir jedoch nicht sicher, ob nicht die eigene Speichervariable im Konstruktor andere Komplikationen mit sich bringt, aber ich werde es wahrscheinlich bald herausfinden ... – jahu

0

Ok, werde ich eine neue Antwort vorschlagen (wenig spät, sorry), dass selbst wenn der Name des Vereins ändert arbeiten. Es wird in der Haupttabelle für den Wert aussieht Diese Methode wird für den Verein Eigenschaft der Haupteinheit sucht und dann

. Stellen Sie sich Folgendes vor:

Tabelle: Orders referenziert mit Tabelle Customers von Orders.CustomerID entspricht Customers.Id. Also übergeben wir die Meta-Informationen der Haupttabelle, das Feld CustomerID (welches das referenzierte Feld ist) und das Feld Name (was der Wert ist, den wir wollen).

/// <summary> 
/// Gets the value of "referencedValueFieldName" of an associated table of the "fieldName" in the "mainTable". 
/// This is equivalent of doing the next LINQ query: 
/// var qryForeignValue = 
///  from mt in modelContext.mainTable 
///  join at in modelContext.associatedTable 
///  on mt.fieldName equals at.associatedField 
///  select new { Value = at.referencedValueField } 
/// </summary> 
/// <param name="mainTable">Metadata of the table of the fieldName's field</param> 
/// <param name="fieldName">Name of the field of the foreign key</param> 
/// <param name="referencedValueFieldName">Which field of the foreign table do you the value want</param> 
/// <returns>The value of the referenced table</returns> 
/// <remarks>This method only works with foreign keys of one field.</remarks> 
private Object GetForeignValue(MetaTable mainTable, string fieldName, string referencedValueFieldName) { 
    Object resultValue = null; 
    foreach (MetaDataMember member in mainTable.RowType.DataMembers) { 
    if ((member.IsAssociation) && (member.Association.IsForeignKey)) { 
     if (member.Association.ThisKey[0].Name == fieldName) { 
     Type associationType = fPointOfSaleData.GetType(); 
     PropertyInfo associationInfo = associationType.GetProperty(member.Name); 
     if (associationInfo == null) 
      throw new Exception("Association property not found on member"); 

     Object associationValue = associationType.InvokeMember(associationInfo.Name, BindingFlags.GetProperty, null, fPointOfSaleData, null); 

     if (associationValue != null) { 
      Type foreignType = associationValue.GetType(); 
      PropertyInfo foreignInfo = foreignType.GetProperty(referencedValueFieldName); 
      if (foreignInfo == null) 
      throw new Exception("Foreign property not found on assiciation member"); 

      resultValue = foreignType.InvokeMember(foreignInfo.Name, BindingFlags.GetProperty, null, associationValue, null); 
     } 

     break; 
     } 
    } 
    } 
    return resultValue; 
} 

Und der Ruf:

 AttributeMappingSource mapping = new System.Data.Linq.Mapping.AttributeMappingSource(); 
     MetaModel model = mapping.GetModel(typeof(WhateverClassesDataContext)); 
     MetaTable table = model.GetTable(typeof(Order)); 
     Object value = GetForeignValue(table, "CustomerId" /* In the main table */, "Name" /* In the master table */); 

Das Problem ist, dass mit nur einem Referenzfeld mit Fremdschlüssel funktioniert nur. Aber das Wechseln zu mehreren Schlüsseln ist ziemlich trivial.

Dieses Verfahren ist ein Wert eines Feldes der Haupttabelle zu erhalten, können Sie verändert das ganze Objekt zurückzukehren.

PS: Ich denke, dass ich einige Fehler über mein Englisch machen, ist es für mich sehr schwierig ist.

0

Diese Frage kam in einem vor langer Zeit, aber ich lief in dieses Problem. Ich benutze eine DBML und löste dieses Problem, indem ich die Beziehungen bearbeite. Wenn Sie die ParentProperty erweitern, können Sie den Eigenschaftennamen festlegen, indem Sie die Name-Eigenschaft ändern.

Hier ist die XML-Daten aus dem DBML (Mitglied Attribute geändert):

<Association Name="State_StateAction1" Member="DestinationState" ThisKey="DestinationStateId" OtherKey="Id" Type="State" IsForeignKey="true" /> 
0

Hier ist eine Variante der Ocelot20 Version:

public partial class ProblemClass 
{ 
    partial void OnCreated() 
    { 
     this._MyNewBetterName = default(EntityRef<FKType>); 
    } 
    protected EntityRef<FKType> _MyNewBetterName; 

    [Association(Name = "FK__SomeLinkHere", Storage = "_MyNewBetterName", ThisKey = "FK_1_Id", OtherKey = "Id", IsForeignKey = true)] 
    public EntityRef<FKType> MyNewBetterName 
    { 
     get 
     { 
      return this._MyNewBetterName.Entity; 
     } 

     set 
     { 
      this.MyNewBetterName = value; 
     } 
    } 
} 

Damit Sie brauchen nicht einmal das wissen ursprünglicher Speicher Name, aber ich bin mir nicht sicher, ob der Setter funktioniert (ich habe nur Getter verwendet, aber es hat wie ein Charme funktioniert). Sie können diese Beziehungsdefinition sogar in eine Basisklasse packen und sie partiell erben lassen (falls Sie die Beziehung zwischen mehreren Modellen \ kontexten wiederverwenden müssen, sollte dies einfacher sein), aber der Haken ist, dass Sie in jedem Element OnCreated() definieren müssen teilweise, da diese in C# (see this) nicht vererbt werden können. Diese