Уровень доступа к данным в нашем приложении будет использовать функциональность UDT Oracle. Мы будем только передавать объекты UDT в базу данных и из нее.
На данный момент мы генерируем пользовательские классы, используя функцию, поставляемую с ODP.NET (которая создает действительно ужасно выглядящий класс, который нам действительно не нужен в нашей кодовой базе).
Затем мы используем отдельный класс отображения для сопоставления пользовательского класса с одним из наших бизнес-объектов (и обратно при сохранении).
Я пытаюсь найти лучший способ сделать это.
Я думал, что просто покончу с сгенерированными классами и напишу класс отображения, который реализует IOracleCustomType. Методы From / ToCustomObject будут затем отображаться из моего UDT в мои бизнес-объекты.
Однако, это вызвало у меня проблемы, когда я попробовал это - я получил ошибку «Атрибут объекта не сопоставлен с элементом пользовательского типа».
Похоже, что для двух методов мне также нужны атрибуты в моем классе отображения - по одному атрибуту для каждого элемента в UDT.
Например - рабочий процесс UDT содержит три элемента - статус, время создания и созданный.
Мой UDT хорош и прост:
TYPE workflow_type AS OBJECT
(status VARCHAR2(8)
,created_by VARCHAR2(30)
,created_datetime DATE
);
Как и бизнес-объект, в котором я хочу оказаться:
public class Workflow
{
/// <summary>
/// Gets the status of the workflow.
/// </summary>
/// <value>The status.</value>
public string Status { get; private set; }
/// <summary>
/// Gets the Windows Logon Id of the user performing the action
/// </summary>
public string CreatedBy{ get; private set; }
/// <summary>
/// Gets the time of the action
/// </summary>
public DateTime CreatedTime { get; private set; }
}
Я хочу перейти от одного к другому, не добавляя код Oracle в бизнес-объект.
Поэтому я подумал о создании класса отображения, подобного этому:
public class WorkFlowMapper : IOracleCustomType
{
public BusinessObjects.WorkFlow BusinessObject {get; private set;}
public WorkFlowMapper(BusinessObjects.WorkFlow businessObject)
{
BusinessObject = businessObject;
}
public WorkFlowMapper(){}
public void FromCustomObject(OracleConnection con, IntPtr pUdt)
{
OracleUdt.SetValue(con, pUdt, "STATUS", BusinessObject.Status);
OracleUdt.SetValue(con, pUdt, "CREATED_BY", BusinessObject.CreatedBy);
OracleUdt.SetValue(con, pUdt, "CREATED_DATETIME", BusinessObject.CreatedTime);
}
public void ToCustomObject(OracleConnection con, IntPtr pUdt)
{
BusinessObject = new BusinessObjects.WorkFlow(
(string)OracleUdt.GetValue(con, pUdt, "STATUS"),
(string)OracleUdt.GetValue(con, pUdt, "CREATED_BY"),
(string)OracleUdt.GetValue(con, pUdt, "CREATED_DATETIME")
);
}
}
// Factory to create an object for the above class
[OracleCustomTypeMappingAttribute("MYUSER.WORKFLOW_TYPE")]
public class CurrencyExposureFactory : IOracleCustomTypeFactory
{
public virtual IOracleCustomType CreateObject()
{
WorkFlowMapper obj = new WorkFlowMapper();
return obj;
}
}
Но это не работает благодаря требованию о необходимости OracleObjectMappingAttribute для каждого отображаемого атрибута (как в сгенерированных классах ODP.NET).
Это кажется действительно глупым, поскольку я не буду использовать их вообще.
Фактически, я могу заставить свой класс отображения работать, просто добавив три строки:
[OracleObjectMappingAttribute("STATUS")] public string a;
[OracleObjectMappingAttribute("CREATED_BY")] public string b;
[OracleObjectMappingAttribute("CREATED_DATETIME")] public DateTime c;
Конечно, должен быть лучший способ, чем положить такой ужасный взлом? В конце концов, эти переменные никогда не используются вообще - ODP.NET, похоже, просто нужен для того, чтобы получить тип для сопоставления, - но я бы подумал, что это может быть достигнуто другим способом.
Мысли?