Система метаданных EF6 довольно сложна, вероятно, из-за попытки охватить слишком много сценариев - сначала база данных, сначала код, а потом модель.У них есть отдельные метаданные, организованные в так называемые пространства данных - модель хранилища, объектная модель и концептуальная модель, а также сопоставления между ними.
Проблема в том, что стандартный генератор EF6 T4 использует концептуальную модель.Это потому, что ExecuteFunction
и CreateQuery
работают с EntityCommand
s (Entity SQL), которые впоследствии преобразуются в команды "store" (необработанный SQL).В то время как ExecuteStoreCommand[Async]
и ExecuteStoreQuery[Async]
работают напрямую с командами "store" (сырой SQL).
Так что вам нужен доступ к модели "store".Обратите внимание, что как «концептуальная», так и «магазинная» модели содержат EdmFunction
объекты, но их имена различны, так же как и имена параметров, типы и т. Д. А поскольку Schema
имеет смысл только для «store» (базы данных), поэтомувы всегда получаете null
от концептуальной модели.
Вот как вы можете загрузить и получить EdmFunction
с из режима хранилища.Стандартный шаблон EF6 T4 включает в себя файл с именем EF6.Utility.CS.ttinclude
, который содержит множество помощников, используемых при генерации кода.Одним из них является класс EdmMetadataLoader
с методом CreateEdmItemCollection
, который используется стандартным шаблоном для загрузки концептуальной модели из EDMX.Его можно использовать как основу для извлечения нужного нам метода, который выглядит следующим образом (добавьте его в конец измененного Context.tt внутри раздела помощников по коду - перед последним закрытием #>
):
private static StoreItemCollection CreateStoreItemCollection(string sourcePath, IDynamicHost host, System.Collections.IList errors)
{
var root = XElement.Load(host.ResolvePath(sourcePath), LoadOptions.SetBaseUri | LoadOptions.SetLineInfo);
var schemaElement = root.Elements()
.Where(e => e.Name.LocalName == "Runtime")
.Elements()
.Where(e => e.Name.LocalName == "StorageModels")
.Elements()
.Where(e => e.Name.LocalName == "Schema")
.FirstOrDefault() ?? root;
if (schemaElement != null)
{
using (var reader = schemaElement.CreateReader())
{
IList<EdmSchemaError> schemaErrors;
var itemCollection = StoreItemCollection.Create(new[] { reader }, null, null, out schemaErrors);
foreach (var error in schemaErrors)
{
errors.Add(
new CompilerError(
error.SchemaLocation ?? sourcePath,
error.Line,
error.Column,
error.ErrorCode.ToString(CultureInfo.InvariantCulture),
error.Message)
{
IsWarning = error.Severity == EdmSchemaErrorSeverity.Warning
});
}
return itemCollection ?? new StoreItemCollection();
}
}
return new StoreItemCollection();
}
Затем найдите строку
var itemCollection = loader.CreateEdmItemCollection(inputFile);
и вставьте следующую строку после нее
var storeItemCollection = CreateStoreItemCollection(inputFile, textTransform.Host, textTransform.Errors);
Теперь вы можете заменить стандартную
foreach (var edmFunction in container.FunctionImports)
{
WriteFunctionImport(typeMapper, codeStringGenerator, edmFunction, modelNamespace, includeMergeOption: false);
}
на
var functions = storeItemCollection
.GetItems<EdmFunction>()
.Where(f => !f.IsFromProviderManifest)
.ToList();
foreach (var edmFunction in functions)
{
#>
// [<#=edmFunction.Schema ?? ""#>].[<#=edmFunction.Name#>]
<#
}
Тело просто выводит комментарий с [Схема]. [Имя] каждого импорта функции db, чтобы доказать правильное свойство edmFunction.Schema
(цель вопроса).Замените его фактической генерацией кода.
В случае, если вам нужны как концептуальные (код), так и определения хранения (дБ) функции, вы можете создать StorageMappingItemCollection
аналогичным образом (единственное отличиеявляется то, что он требует передачи EdmItemCollection
и StoreItemCollection
, которые у вас уже есть в дополнение к xml reader), например (CreateStorageMappingItemCollection
- метод, который вы должны создать и реализовать):
var storageMappingItemCollection = CreateStorageMappingItemCollection(
(EdmItemCollection)itemCollection, storeItemCollection,
inputFile, textTransform.Host, textTransform.Errors);
изатем используйте
var functionImports = storageMappingItemCollection
.GetItems<EntityContainerMapping>()
.SelectMany(m => m.FunctionImportMappings)
.ToList();
, чтобы получить список FunctionImportMapping объектов, имеющих два свойства типа EdmFunction
: FunctionImport (концептуальная модель) и TargetFunction (модель хранилища).
Обновление Вам действительно нужно использовать вышеупомянутый подход "отображения".FunctionImport
предоставляет необходимую информацию для определения метода C # (имя, аргументы, тип возвращаемого значения), тогда как TargetFunction
предоставляет информацию, необходимую для вызова функции / процедуры db.
Таким образом, вспомогательный метод выглядит следующим образом:
private static StorageMappingItemCollection CreateStorageMappingItemCollection(EdmItemCollection edmItemCollection, StoreItemCollection storeItemCollection, string sourcePath, IDynamicHost host, System.Collections.IList errors)
{
var root = XElement.Load(host.ResolvePath(sourcePath), LoadOptions.SetBaseUri | LoadOptions.SetLineInfo);
var schemaElement = root.Elements()
.Where(e => e.Name.LocalName == "Runtime")
.Elements()
.Where(e => e.Name.LocalName == "Mappings")
.Elements()
.Where(e => e.Name.LocalName == "Mapping")
.FirstOrDefault() ?? root;
if (schemaElement != null)
{
using (var reader = schemaElement.CreateReader())
{
IList<EdmSchemaError> schemaErrors;
var itemCollection = StorageMappingItemCollection.Create(edmItemCollection, storeItemCollection, new[] { reader }, null, out schemaErrors);
foreach (var error in schemaErrors)
{
errors.Add(
new CompilerError(
error.SchemaLocation ?? sourcePath,
error.Line,
error.Column,
error.ErrorCode.ToString(CultureInfo.InvariantCulture),
error.Message)
{
IsWarning = error.Severity == EdmSchemaErrorSeverity.Warning
});
}
if (itemCollection != null) return itemCollection;
}
}
return new StorageMappingItemCollection(edmItemCollection, storeItemCollection);
}
и пример использования:
var storageMappingItemCollection = CreateStorageMappingItemCollection(
(EdmItemCollection)itemCollection, storeItemCollection,
inputFile, textTransform.Host, textTransform.Errors);
var functionImports = storageMappingItemCollection
.GetItems<EntityContainerMapping>()
.SelectMany(m => m.FunctionImportMappings)
.ToList();
foreach (var item in functionImports)
{
#>
// <#=item.FunctionImport.Name#> => [<#=item.TargetFunction.Schema ?? ""#>].[<#=item.TargetFunction.Name#>]
<#
}