7

編集-実際の問題をより適切に反映するために質問をクリーンアップします。

SQLMetalを使用して、SQLServerデータベースからデータベースクラスを生成しています。最近、同じテーブルを指す複数の外部キーを持つテーブルを追加する必要がありました。LINQPadを使用して新しいテーブルを試してみると、次のように両方の外部キーのプロパティにアクセスできました。

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

...それは私がそれを期待する方法です。問題は、SQLMetalによって生成されたクラスが次のプロパティを生成することです。

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

これで、生成されたクラスを変更できるので、FKBTableNameGoesHereはFK_Bになりますが、生成されたファイルはさまざまなチームメンバーによって頻繁に変更されるため、非常に面倒ですこれに対する簡単な修正はありますか?

前もって感謝します。

編集2 したがって、解決策は、自分が望む名前のプロパティを持つ部分クラスを作成し、ゲッター/セッターが不適切な名前のプロパティを指すようにすることだと思いました。これは選択には有効でしたが、where句などでは使用しませんでした。誰もが解決策を持っていますか?

4

4 に答える 4

4

したがって、私の解決策は、別の部分クラスを追加し、get/setが奇妙な名前のFKBTableNameGoesHereプロパティを指すプロパティを追加することでした。そうすれば、生成されたクラスを変更し続ける必要はありません。問題を正確に解決するわけではありませんが、プロパティの意味を開発者に明確にする必要があります。誰かがその解決策に潜在的な問題を見ていますか?

編集-したがって、これは明らかにデータを選択するためにのみ機能し、それに基づいてフィルタリングすることはできません。思っていたほど簡単に修正できませんでした。他に何か提案はありますか?

編集2-ジーゼ、これはやや一般的な問題だと思ったが、私はそうは思わない。とにかく、私はこれで正しい軌道に乗っていたことがわかりました。私はこの投稿を見つけました:

同じテーブルへの複数の外部キー

舞台裏で起こっていることよりもおそらくもっとたくさんあるので、私は別のプロパティのゲッター/セッターに直接リンクすることはできないという考えを私に与えました。この男の解決策は正確には答えではありませんでしたが、それは私を厳密な方向に送りました。アソシエーション属性を追加することは、最終的にそれを行ったことです。

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

よりクリーンな解決策を思い付くことができる人のために、賞金を開いたままにしておくつもりです。

于 2010-09-20T15:31:45.883 に答える
0

わかりました。協会の名前が変わっても機能する新しい回答を提案します(少し遅れて申し訳ありません)。

このメソッドは、メインエンティティの関連付けプロパティを検索してから、マスターテーブルの値を検索します。想像してみろ:

テーブル:equalsによってOrdersテーブルで参照されます。したがって、メインテーブルのメタ情報、フィールド(参照されるフィールド)、およびフィールド(必要な値)を渡します。CustomersOrders.CustomerIDCustomers.IdCustomerIDName

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

そして、呼び出し:

      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 */);

問題は、参照フィールドが1つしかない外部キーでしか機能しないことです。ただし、複数のキーに変更するのは非常に簡単です。

これは、マスターテーブルのフィールドの値を取得するメソッドです。オブジェクト全体を返すように変更できます。

PS:私は自分の英語についていくつかの間違いを犯していると思います、それは私にとって非常に難しいです。

于 2012-05-22T05:51:43.940 に答える
0

この質問はずっと前に出てきましたが、私はちょうどこの問題に遭遇しました。私はDBMLを使用しており、関係を編集することでこの問題を解決しました。ParentPropertyを展開すると、Nameプロパティを変更してプロパティ名を設定できます。

DBMLからのXMLは次のとおりです(Member属性が変更されました)。

  <Association Name="State_StateAction1" Member="DestinationState" ThisKey="DestinationStateId" OtherKey="Id" Type="State" IsForeignKey="true" />
于 2012-07-26T22:07:05.343 に答える
0

Ocelot20のバージョンのバリエーションは次のとおりです。

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

これにより、元のストレージ名を知る必要はありませんが、セッターが機能するかどうかはわかりません(私はゲッターのみを使用しましたが、チャームのように機能しました)。このリレーション定義を基本クラスにパックして、パーシャルに継承させることもできます(複数のモデル/コンテキスト間でリレーションを再利用する必要がある場合は、これにより簡単になります)が、キャッチは、OnCreated()各パーシャル内で定義する必要がありますそれらはc#で継承できないため(これを参照)。

于 2014-10-13T10:41:15.890 に答える