EF4: получить имена связанных столбцов из NavigationProperty EDMX - PullRequest
9 голосов
/ 20 марта 2011

Я генерирую POCO (скажем, они являются подклассами MyEntityObject ), используя шаблон T4 из файла EDMX.

У меня есть 3 объекта, например:

  • MyTable1 (PrimaryKey: MyTable1ID)
  • MyTable2 (PrimaryKey: MyTable2ID)
  • MyTable3 (PrimaryKey:MyTable3ID)

Эти объекты имеют следующие отношения:

MyTable1.MyTable1ID <=> MyTable2.MyTable1ID (MyTable1ID является внешним ключом для MyTable1)

MyTable2.MyTable2ID <=> MyTable3.MyTable2ID (MyTable2ID - это внешний ключ MyTable2)

Или в другом представлении:

MyTable1 <= MyTable2 <= MyTable3 </p>

Я хочу извлечь все отношения внешнего ключа

NavigationProperty[] foreignKeys = entity.NavigationProperties.Where(np => np.DeclaringType == entity && ((AssociationType)np.RelationshipType).IsForeignKey).ToArray();
forewach (NavigationProperty foreignKey in foreignKeys)
{
    // generate code....
}

Мой вопрос: Как извлечь имена столбцов, которые связаны между двумя объектами?

Примерно так:

void GetLinkedColumns(MyEntityObject table1, MyEntityObject table2, out string fkColumnTable1, out string fkColumnTable2)
{
    // do the job
}

В примере

string myTable1Column;
string myTable2Column;
GetLinkedColumns(myTable1, myTable2, out myTable1Column, out myTable2Column);

результат должен быть

myTable1Column = "MyTable1ID";
myTable2Column = "MyTable2ID";

Ответы [ 3 ]

6 голосов
/ 22 апреля 2011

Первый ответ работает, если столбцы внешнего ключа представлены как свойства в вашей концептуальной модели. Кроме того, метод GetSourceSchemaTypes () доступен только в некоторых текстовых шаблонах, включенных в EF, поэтому полезно знать, что делает этот метод.

Если вы хотите всегда знать имена столбцов, вам потребуется загрузить AssociationType из модели хранилища следующим образом:

// Obtain a reference to the navigation property you are interested in
var navProp = GetNavigationProperty();

// Load the metadata workspace
MetadataWorkspace metadataWorkspace = null;
bool allMetadataLoaded =loader.TryLoadAllMetadata(inputFile, out metadataWorkspace);

// Get the association type from the storage model
var association = metadataWorkspace
    .GetItems<AssociationType>(DataSpace.SSpace)
    .Single(a => a.Name == navProp.RelationshipType.Name)

// Then look at the referential constraints
var toColumns = String.Join(",", 
    association.ReferentialConstraints.SelectMany(rc => rc.ToProperties));
var fromColumns = String.Join(",", 
    association.ReferentialConstraints.SelectMany(rc => rc.FromProperties));

В этом случае загрузчик - это MetadataLoader, определенный в EF.Utility.CS.ttinclude, а inputFile - это стандартная строковая переменная, определяющая имя файла .edmx. Они уже должны быть объявлены в вашем текстовом шаблоне.

2 голосов
/ 09 апреля 2013

Этот код отлично работает на моей Visual Studio 2012

<#@ template language="C#" debug="true" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#
string inputFile = @"DomainModel.edmx";

MetadataLoader loader = new MetadataLoader(this);

EdmItemCollection ItemCollection = loader.CreateEdmItemCollection(inputFile);

foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
{
    foreach (NavigationProperty navProperty in entity.NavigationProperties)
    {
        AssociationType association = ItemCollection.GetItems<AssociationType>().Single(a => a.Name == navProperty.RelationshipType.Name);
        string fromEntity = association.ReferentialConstraints[0].FromRole.Name;
        string fromEntityField = association.ReferentialConstraints[0].FromProperties[0].Name;
        string toEntity = association.ReferentialConstraints[0].ToRole.Name;
        string toEntityField = association.ReferentialConstraints[0].ToProperties[0].Name;
    }
}

#>
2 голосов
/ 20 апреля 2011

Не знаю точно, хотите ли вы сгенерировать код, используя столбцы или нет, но это может частично помочь ответить на ваш вопрос ( Как я могу извлечь имена столбцов, которые связаны между двумя объектами? )...

NavigationProperty[] foreignKeys = entity.NavigationProperties
  .Where(np => np.DeclaringType == entity &&
          ((AssociationType)np.RelationshipType).IsForeignKey).ToArray();

foreach (NavigationProperty foreignKey in foreignKeys)
{
   foreach(var rc in GetSourceSchemaTypes<AssociationType>()
       .Single(x => x.Name == foreignKey.RelationshipType.Name)
       .ReferentialConstraints)
   {
       foreach(var tp in rc.ToProperties)
           WriteLine(tp.Name);
       foreach(var fp in rc.FromProperties)
           WriteLine(fp.Name);
   }
}
...