Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

Расширить EDMX?

388  
Murr патриот22.01.19 12:49
Murr
NEW 22.01.19 12:49 

Снова выплывает вопросик по расширению EDMX-файла.

https://foren.germany.ru/arch/programmer/f/32296755.html?C...


Смотрю текущую имплементацию ЕФ6 и сильно не понимаю почему делали так как делали.

Вот например:

https://github.com/jradxl/Entity-Framework-Code-Generation...

это всего лишь враппер над текущим базовым классом. Все, что делается, помимо врапа методов и пропертей, - подстановка NullHost если Хост не задан. Не понимаю зачем это делается - всегда есть возможность сказать, что Хост обязателен - для этого есть соответствующий аттрибутик.


Ну и нахрена надо извращаться?

#1 
Murr патриот23.01.19 18:30
Murr
23.01.19 18:30 
в ответ Murr 22.01.19 12:49

Нашел таки частичную спеку на ЕДМХ.

https://docs.microsoft.com/en-us/ef/ef6/modeling/designer/...


вроде 3 из 5 мне известных.

Как загружается коллекция - все еще не разобрался... и как расширить - тоже.


На ход - видимо надо добавлять свой намеспасе и писать свое туда...


#2 
Murr патриот24.01.19 15:46
Murr
NEW 24.01.19 15:46 
в ответ Murr 23.01.19 18:30

Ковыряю написанную "билли" загрузку из ХМЛа...


Кто ковырялся в хмл-сериализации должен помнить как там прописываются атрибуты классов и пропертей и как потом конфигурится маппинг имен элементов на имеющиеся типы...


Ну а вот так делает "билли":


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. Посмотрел иерархию классов... что-то странное... похоже проблемы с архитектором...

#3 
Murr патриот25.01.19 12:30
Murr
NEW 25.01.19 12:30 
в ответ Murr 24.01.19 15:46

Пока копался в описаниях и ссылках нашел один интересный файлик:

https://winprotocoldoc.blob.core.windows.net/productionwin...


Утверждается, что содержит все используемые мелкомягкими спецификации...

Весит около полугига, внутри довольно много ПДФок.

Спеки на SSDL там нашел.

#4 
Murr патриот25.01.19 17:22
Murr
NEW 25.01.19 17:22 
в ответ Murr 25.01.19 12:30

Веселости... есть тоолузка 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;

После чего на генерации начинается крик об том, что что-то не определено...


Что плохо - нужные части нельзя загрузить отдельно - намеспасы не свяжутся...

Хотя... надо попробовать протолкнуть... но иметь их описанными и не иметь загруженными... нонсенс... нахрен тогда описывать...


Нее, не проталкивается... циклическая ссылка мешает...


А между тем - тоолозка аккурат из комплекта студии или из студийного СДК и соурсники из мелкомягкой документации...

#5 
Murr патриот05.02.19 17:04
Murr
NEW 05.02.19 17:04 
в ответ Murr 25.01.19 17:22

Имеем достаточно простой код:

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.

Нужда в них нулевая, но вставляютя... может другой конструктор надо пользовать - у билли как всегда много не явного...

#6