Многочисленные внешние ключи SQLMetal, указывающие на одну проблему таблицы - PullRequest
6 голосов
/ 17 сентября 2010

Редактировать - Очистить вопрос, чтобы лучше отразить актуальную проблему:

Я использую SQLMetal для генерации классов базы данных из нашей базы данных SQL Server. Недавно мне нужно было добавить таблицу с несколькими внешними ключами, указывающими на одну и ту же таблицу. Используя 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 голосов
/ 20 сентября 2010

Итак, мое решение состояло в том, чтобы просто добавить еще один частичный класс и добавить свойство с 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;
        }
    }
}

Собирается оставить награду открытой для всех, кто еще может найти более чистое решение.

0 голосов
/ 13 октября 2014

Вот вариант версии 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 # ( см. это ).

0 голосов
/ 27 июля 2012

Этот вопрос возник очень давно, но я столкнулся с этой проблемой.Я использую DBML, и я решил эту проблему путем редактирования отношений.Если вы раскрываете ParentProperty, вы можете установить имя свойства, изменив свойство Name.

Вот XML-код из DBML (атрибут Member изменился):

  <Association Name="State_StateAction1" Member="DestinationState" ThisKey="DestinationStateId" OtherKey="Id" Type="State" IsForeignKey="true" />
0 голосов
/ 22 мая 2012

Хорошо, я предложу новый ответ (немного поздно, извините), который будет работать, даже если имя ассоциации изменится.

Этот метод будет искать свойство ассоциации основного объекта, а затем будет искать значение в главной таблице. Представьте себе, что:

Таблица: Orders ссылка на таблицу Customers на Orders.CustomerID равна Customers.Id. Таким образом, мы передаем мета-информацию основной таблицы, поле CustomerID (которое является ссылочным полем) и поле Name (которое является желаемым значением).

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

Проблема в том, что работает только с внешними ключами только с одним указанным полем. Но переключение на несколько клавиш довольно тривиально.

Это метод для получения значения поля основной таблицы, который можно изменить, чтобы он возвращал весь объект.

PS: Я думаю, что делаю некоторые ошибки в своем английском, это довольно сложно для меня.

...