Расширить EDMX?
Снова выплывает вопросик по расширению EDMX-файла.
https://foren.germany.ru/arch/programmer/f/32296755.html?C...
Смотрю текущую имплементацию ЕФ6 и сильно не понимаю почему делали так как делали.
Вот например:
https://github.com/jradxl/Entity-Framework-Code-Generation...
это всего лишь враппер над текущим базовым классом. Все, что делается, помимо врапа методов и пропертей, - подстановка NullHost если Хост не задан. Не понимаю зачем это делается - всегда есть возможность сказать, что Хост обязателен - для этого есть соответствующий аттрибутик.
Ну и нахрена надо извращаться?
Нашел таки частичную спеку на ЕДМХ.
https://docs.microsoft.com/en-us/ef/ef6/modeling/designer/...
вроде 3 из 5 мне известных.
Как загружается коллекция - все еще не разобрался... и как расширить - тоже.
На ход - видимо надо добавлять свой намеспасе и писать свое туда...
Ковыряю написанную "билли" загрузку из ХМЛа...
Кто ковырялся в хмл-сериализации должен помнить как там прописываются атрибуты классов и пропертей и как потом конфигурится маппинг имен элементов на имеющиеся типы...
Ну а вот так делает "билли":
protected override bool HandleElement(XmlReader reader){if (base.HandleElement(reader)){return true;}else if (CanHandleElement(reader, XmlConstants.Key)){HandleKeyElement(reader);return true;}else if (CanHandleElement(reader, XmlConstants.NavigationProperty)){HandleNavigationPropertyElement(reader);return true;}else if (CanHandleElement(reader, XmlConstants.ValueAnnotation)&& Schema.DataModel == SchemaDataModelOption.EntityDataModel){// EF does not support this EDM 3.0 element, so ignore it.SkipElement(reader);return true;}else if (CanHandleElement(reader, XmlConstants.TypeAnnotation)&& Schema.DataModel == SchemaDataModelOption.EntityDataModel){// EF does not support this EDM 3.0 element, so ignore it.SkipElement(reader);return true;}return false;}
Вот так простенько:
- прописали в отдельный файл возможные имена элементов
- прописали для каждого элемента отдельный хандлер
- в хандлере прописали детальный порядок обработки атрибутов и чилдов...
ни расширить, ни поменять... только переписывать...
чтобы просто добавить один атрибут надо будет дописывать в 4-6 местах...
ладно хоть оставили возможность поработать с десериализированными атрибутами и чилдами...
P.S. Ну и кому надо вспоминать автоматические сериализаторы?
P.P.S. Посмотрел иерархию классов... что-то странное... похоже проблемы с архитектором...
Пока копался в описаниях и ссылках нашел один интересный файлик:
https://winprotocoldoc.blob.core.windows.net/productionwin...
Утверждается, что содержит все используемые мелкомягкими спецификации...
Весит около полугига, внутри довольно много ПДФок.
Спеки на SSDL там нашел.
Веселости... есть тоолузка xsd.exe далее ее код(часть)
Простой код загрузки схемы:
XmlTextReader xmlTextReader = new XmlTextReader(location, (new StreamReader(location)).BaseStream){XmlResolver = null};XmlSchema xmlSchema = XmlSchema.Read(xmlTextReader, new ValidationEventHandler(ValidationCallbackWithErrorCode));
Дает вполне корректную загрузку схемы.
Есть там пропертя Инклюдес - содержит аккурат те ссылки, которые которые были в документе.
Пропертя при данной конфигурации не разрезолвливаются - их надо дополнительно прорабатывать...
Следующий код поставил меня в тупик:
private static void CollectIncludes(XmlSchema schema, Uri baseUri, Hashtable includeSchemas, string topUri){if (schema == null){return;}foreach (XmlSchemaExternal include in schema.Includes){string schemaLocation = include.SchemaLocation;if (!(include is XmlSchemaImport)){if (include.Schema != null || schemaLocation == null || schemaLocation.Length <= 0){continue;}Uri uri = Xsd.ResolveUri(baseUri, schemaLocation);string lower = uri.ToString().ToLower(CultureInfo.InvariantCulture);if (topUri != lower){XmlSchema item = (XmlSchema)includeSchemas[lower];if (item == null){string str = schemaLocation;string pathFromUri = Xsd.GetPathFromUri(uri);bool flag = (pathFromUri == null ? false : File.Exists(pathFromUri));if (File.Exists(str)){if (flag){string lower1 = Path.GetFullPath(str).ToLower(CultureInfo.InvariantCulture);if (lower1 != pathFromUri){Xsd.Warning(Microsoft.DevApps.WebServices.XsdResources.Res.GetString("MultipleFilesFoundMatchingInclude4", new object[] { schemaLocation, Xsd.GetPathFromUri(baseUri), lower1, pathFromUri }));}}}else if (flag){str = pathFromUri;}item = Xsd.ReadSchema(str, false);includeSchemas[lower] = item;Xsd.CollectIncludes(item, uri, includeSchemas, topUri);}if (item == null){continue;}include.Schema = item;include.SchemaLocation = null;}else{include.Schema = new XmlSchema(){TargetNamespace = schema.TargetNamespace};include.SchemaLocation = null;return;}}else{include.SchemaLocation = null;}}}
Вроде все не сложно и даже понятно, но...
То, что описано как импортируемое, имеет тип... XmlSchemaImport
Соответственно, весь метод только и делает, что стирает include.SchemaLocation = null;
После чего на генерации начинается крик об том, что что-то не определено...
Что плохо - нужные части нельзя загрузить отдельно - намеспасы не свяжутся...
Хотя... надо попробовать протолкнуть... но иметь их описанными и не иметь загруженными... нонсенс... нахрен тогда описывать...
Нее, не проталкивается... циклическая ссылка мешает...
А между тем - тоолозка аккурат из комплекта студии или из студийного СДК и соурсники из мелкомягкой документации...
Имеем достаточно простой код:
XmlSchemaImporter xmlSchemaImporter = new XmlSchemaImporter(xmlSchemas, options, provider, context);
Смысл параметров:
- хмлСхемы - коллекция хсд-схем
- оптионс - параметры генерации - почему сюда, а не к провидеру - не знаю
- провидер - собсвенно конвертов в определенный язык
- контехт - просто место куда временно складывается всякая мелкая фигня в процессе генерации.
Импортер, помимо параметров при создании, еще имеет коллекцию расширений - можно добавить стандартные распознаватели или написать свои. Написать свой - не проблема, но писать что-то большое не очень хочется.
Импортер и расширения, с точки зрения генерации кода, строят большой список имен классов для которых надо сгенерировать код. Для запутанности имена классов обернуты в XmlTypeMapping. Попутно с построением списка немного меняются данные в контексте и провайдере. Детали - не понятны, описания чего и как надо менять пока не нашел. Есть примеры - надо ковырять.
Ах, да - маппинг - маппинг можно поменять в расширении импоретра. Или после.
Одна проблема - после построения списка имен классов со всех схем, для каждого имени выполняется
XmlTypeMapping xmlTypeMapping = schemaImporter.ImportTypeMapping(value.QualifiedName);arrayLists.Add(xmlTypeMapping);
Тут аккурат случается всеми любимый "Circular References" - который по спецификации может иметь место и пока Я не нашел чем его прибить в автоматическом режиме.
Дальше идет генеарция.
XmlCodeExporter xmlCodeExporter = new XmlCodeExporter(codeNamespace, codeCompileUnit, provider, options, null);
новые параметры:
- кодеНамеспасе - обычный намеспасе в который надо оборачивать код
- кодеКомпилеЮнит - дерево для хранения заготовок кода - идея в том, чтобы разделить то что должно быть сгенерировано, от самого процесса генерации. Т.е. тут хранится указание на то, что надо сгенерировать проперть, а конкретная генерация - ВБ или Шарп - дело провайдера.
- последний нулл - не помню, надо смотреть в доках.
Остальное - из Импортера.
Дальше для каждого элемента из списка классов полученного из Импортера выполняется построение кода класса:
xmlCodeExporter.ExportTypeMapping(typeMapping);
Насколько Я понимаю, для передаваемого тайпМаппинга из набора схем выбирается куча всего, что определяет содержимое генерируемого класса в соответствии с опциями.
Для чего в Импортере и Ехпортире нужен Провайдер - не понимаю - все необходимое пакуется в кодеКомпилеЮнит. Но - передаются и передаются.
Ну и дамп:
provider.GenerateCodeFromCompileUnit(codeCompileUnit, textWriter, null);
Чего пишу то - процесс - понятен (неточности - возможны, но не существенны).
Так вопросик - как решить проблему с циркулярной ссылкой? В смысле - не редактируя хсд-ку, а чисто програмно - файл то с хсд-шкой - конечен - должна существовать процедура построения тайпМапперо'ов без зацикливания...
Код Импортера, разумеется, есть, но там довольно много и запутано...
Да, забыл совсем... по дефаулту, хотя и не описано, в расширения импортера грузятся распознователи некоторых типов данных из System.Data.dll.
Нужда в них нулевая, но вставляютя... может другой конструктор надо пользовать - у билли как всегда много не явного...