public override void Execute(XTriggerArgs args, IXExecutionContext context) { DomainObjectData xobj = args.TriggeredObject; // если изменилось значение признака "Архивное", проверим отсутствие у подразделения работающих сотрудников или не архивных департаментов. bool bUpdateIsArchive = xobj.HasUpdatedProp("IsArchive"); if (bUpdateIsArchive) { bool newValue = (bool)xobj.GetUpdatedPropValue("IsArchive"); if (!xobj.IsNew && newValue) { // 1. Проверим, что все сотрудники (во всех вложенных департаментах) уволены XDbCommand cmd = context.Connection.CreateCommand(@" SELECT 1 FROM dbo.Department d_s WITH(NOLOCK) JOIN dbo.Department d WITH(NOLOCK) ON d.LIndex >= d_s.LIndex AND d.RIndex <= d_s.RIndex AND d.Organization = d_s.Organization JOIN Employee e WITH(NOLOCK) ON (d.ObjectID = e.Department) and (e.WorkEndDate is null) WHERE d_s.ObjectID = @ObjectID " ); cmd.Parameters.Add("ObjectID", DbType.Guid, ParameterDirection.Input, false, xobj.ObjectID); if (cmd.ExecuteScalar() != null) { throw new XBusinessLogicException("Департамент не может быть переведен с состояние \"Архивное\", так как содержит работающих сотрудников"); } } // добавим в датаграмму подчиненные департаменты UpdateChildDepartments(context.Connection, args.DataSet, xobj.ObjectID, newValue); } }
protected Guid GetScalarObjectPropValueFromDB(XStorageConnection con, string sObjectType, Guid ObjectID, string[] aPathParts, int nStartIndex) { string sObjectType_cur = sObjectType; Guid oid_cur = ObjectID; string sQuery = "@ObjectID"; object vPropValue; // значение свойства for (int nIndex = nStartIndex; nIndex < aPathParts.Length; ++nIndex) { sQuery = String.Format("SELECT {0} FROM {1} WHERE ObjectID = ({2})", con.ArrangeSqlName(aPathParts[nIndex]), // 0 - свойство-колонка con.GetTableQName(sObjectType_cur), // 1 - тип-таблица sQuery // 2 - вложенное условие ); sObjectType_cur = getObjectValueTypeName(sObjectType_cur, aPathParts[nIndex], con); } XDbCommand cmd = con.CreateCommand(sQuery); cmd.Parameters.Add("ObjectID", DbType.Guid, ParameterDirection.Input, false, oid_cur); vPropValue = cmd.ExecuteScalar(); if (vPropValue == null) { return(Guid.Empty); } else if (vPropValue is DBNull) { return(Guid.Empty); } return((Guid)vPropValue); }
/// <summary> /// Команда получения данных для фильтра списка тендеров /// </summary> public GetFilterTendersInfoResponse Execute(GetFilterTendersInfoRequest request, IXExecutionContext context) { GetFilterTendersInfoResponse resp = new GetFilterTendersInfoResponse(); using (XDbCommand cmd = context.Connection.CreateCommand()) { // Если идентификатор тендера не задан if (request.SelectedTenderID == Guid.Empty) { cmd.CommandText = @"SELECT TOP 1 ObjectID FROM dbo.Organization with (nolock) WHERE Home <> 0" ; object temp = cmd.ExecuteScalar(); resp.OrganizationID = (temp == null) ? Guid.Empty : (Guid)temp; } // Если задан else { cmd.CommandText = @"SELECT TOP 1 O.ObjectID, T.DocFeedingDate FROM dbo.Tender AS T with (nolock) LEFT JOIN dbo.Lot AS L with (nolock) ON L.Tender = T.ObjectID LEFT JOIN dbo.LotParticipant AS P with (nolock) ON P.Lot = L.ObjectID LEFT JOIN dbo.Organization AS O with (nolock) ON O.ObjectID = P.ParticipantOrganization WHERE O.OwnTenderParticipant <> 0 AND T.ObjectID = @SelectedTenderID" ; // Передадим в параметр ID тендера cmd.Parameters.Add("SelectedTenderID", DbType.Guid, ParameterDirection.Input, false, request.SelectedTenderID); using (IDataReader reader = cmd.ExecuteReader()) { if (reader.Read()) { // Проставим значения ID огранизации и "даты подачи документов" resp.OrganizationID = reader.IsDBNull(0) ? Guid.Empty : reader.GetGuid(0); resp.DocFeedingDate = reader.IsDBNull(1) ? DateTime.MinValue : reader.GetDateTime(1); } else { resp.OrganizationID = Guid.Empty; resp.DocFeedingDate = DateTime.MinValue; } } } } return(resp); }
public override void Execute(XTriggerArgs args, Croc.XmlFramework.Core.IXExecutionContext context) { DomainObjectData xobj = args.TriggeredObject; bool bUpdatedState = xobj.HasUpdatedProp("State"); bool bUpdateIsLocked = xobj.HasUpdatedProp("IsLocked"); if (!bUpdatedState && !bUpdateIsLocked) { return; } // если здесь значит изменилось хотя бы одно из полей: Состояние (State), Дата блокирования списаний (BlockDate) // Теперь надо зачитать предыдущие значения из БД, но только тех свойств, которые обновляются preloadProps(xobj, bUpdatedState, bUpdateIsLocked, context); if (bUpdateIsLocked) { bool oldValue = (bool)xobj.GetLoadedPropValue("IsLocked"); bool newValue = (bool)xobj.GetUpdatedPropValue("IsLocked"); if (oldValue != newValue) { // изменение признака допустимости списания DomainObjectData xobjHistory = getFolderHistoryObject(args.DataSet, xobj); xobjHistory.SetUpdatedPropValue("Event", newValue?FolderHistoryEvents.IsLockedSetToTrue:FolderHistoryEvents.IsLockedSetToFalse); } } if (bUpdatedState) { FolderStates stateOld = (FolderStates)xobj.GetLoadedPropValue("State"); FolderStates stateNew = (FolderStates)xobj.GetUpdatedPropValue("State"); if (stateOld != stateNew) { // состояние изменилось // - проверим на запрещенные переходы checkFolderStateChanging(stateOld, stateNew); DomainObjectData xobjHistory = getFolderHistoryObject(args.DataSet, xobj); FolderHistoryEvents eventType; if (stateNew == FolderStates.Closed) { eventType = FolderHistoryEvents.Closing; } else if (stateNew == FolderStates.Frozen) { eventType = FolderHistoryEvents.Frozing; } else if (stateNew == FolderStates.WaitingToClose) { eventType = FolderHistoryEvents.WaitingToClose; } else // if (stateNew == FolderStates.Open) { eventType = FolderHistoryEvents.Opening; } xobjHistory.SetUpdatedPropValue("Event", eventType); // обработаем переход в состояние "Закрыто": if (!xobj.IsNew && (stateNew == FolderStates.Closed || stateNew == FolderStates.WaitingToClose)) { // 1. Проверим, что все инциденты (во всех вложенных папках) находятся в конечных состояниях XDbCommand cmd = context.Connection.CreateCommand(@" SELECT 1 FROM Folder f_s WITH(NOLOCK) JOIN Folder f WITH(NOLOCK) ON f.LIndex >= f_s.LIndex AND f.RIndex <= f_s.RIndex AND f.Customer = f_s.Customer JOIN Incident i WITH(NOLOCK) ON f.ObjectID = i.Folder JOIN IncidentState i_st WITH(NOLOCK) ON i.State = i_st.ObjectID AND i_st.Category IN (1,2) WHERE f_s.ObjectID = @ObjectID " ); cmd.Parameters.Add("ObjectID", DbType.Guid, ParameterDirection.Input, false, xobj.ObjectID); if (cmd.ExecuteScalar() != null) { throw new XBusinessLogicException("Папка не может быть переведена в состояние \"Закрыто\" или \"Ожидание закрытия\", так как содержит незавершенные инциденты"); } } // добавим в датаграмму подчиненные папки с установленным состоянием новым состояние // Обработка папок зависит от нового состояния fillDataSetWithChildFoldersWithUpdatedState(context.Connection, args.DataSet, xobj.ObjectID, stateNew); } } }
/// <summary> /// Выполняет удаление в БД объектов в списке в порядке их следования в нем /// </summary> /// <param name="xs">Экземпляр XStorageConection</param> /// <param name="disp">Диспетчер запросов</param> /// <param name="aDelObjects">список объектов (типа ObjectToDelete), для которых надо выполнить delete в БД</param> protected virtual int doDelete(XStorageConnection xs, XDbStatementDispatcher disp, ICollection aDelObjects) { int nRowsAffected = 0; // количество удаленных записей bool bForcedMode = false; // признак форсированного удаления (есть хотя бы один объект с незаданным ts) string sTypeNamePrev = String.Empty; // наименование типа предыдущего объекта (в цикле) StringBuilder queryTextBuilder = new StringBuilder(); // построитель оператора delete if (aDelObjects.Count == 0) { return(0); } foreach (XStorageObjectToDelete obj in aDelObjects) { if (obj.TS == -1) { bForcedMode = true; } if (sTypeNamePrev != obj.ObjectType) { // объект нового типа (в т.ч. первый) if (queryTextBuilder.Length > 0) { disp.DispatchStatement(queryTextBuilder.ToString(), true); queryTextBuilder.Length = 0; } queryTextBuilder.AppendFormat("DELETE FROM {0} WHERE {1}={2}", xs.GetTableQName(obj.TypeInfo), // 0 xs.ArrangeSqlName("ObjectID"), // 1 xs.ArrangeSqlGuid(obj.ObjectID) // 2 ); // если для объекта задан TS, добавим условие на него if (obj.AnalyzeTS) { queryTextBuilder.AppendFormat(" AND {0}={1}", xs.ArrangeSqlName("ts"), obj.TS ); } } else { // еще один объект того же типа queryTextBuilder.AppendFormat(" OR {0}={1}", xs.ArrangeSqlName("ObjectID"), // 0 xs.ArrangeSqlGuid(obj.ObjectID) // 1 ); // если для объекта задан TS, добавим условие на него if (obj.AnalyzeTS) { queryTextBuilder.AppendFormat(" AND {0}={1}", xs.ArrangeSqlName("ts"), obj.TS ); } } sTypeNamePrev = obj.ObjectType; } if (queryTextBuilder.Length > 0) { disp.DispatchStatement(queryTextBuilder.ToString(), true); } nRowsAffected = disp.ExecutePendingStatementsAndReturnTotalRowsAffected(); if (!bForcedMode) { if (nRowsAffected != aDelObjects.Count) { // количество удаленных объектов не совпадает с ожидаемым кол-вом. // если в БД остался хотя бы один объект из тех, которые мы удалили, то // это означает, что у него "устарел" ts, следовательно будем ругаться. // Иначе (в БД нет ниодного объект из тех, которые мы удаляли) все хорошо, просто // нас кто-то опередил, но главное результат - все требуемые объекты удалены. sTypeNamePrev = String.Empty; queryTextBuilder = new StringBuilder(); XDbCommand cmd = xs.CreateCommand(); cmd.CommandType = CommandType.Text; foreach (XStorageObjectToDelete obj in aDelObjects) { if (sTypeNamePrev != obj.ObjectType) { // объект нового типа (в т.ч. первый) if (queryTextBuilder.Length > 0) { cmd.CommandText = queryTextBuilder.ToString(); if (Convert.ToInt32(cmd.ExecuteScalar()) > 0) { throw new XOutdatedTimestampException(); } queryTextBuilder.Length = 0; } queryTextBuilder.AppendFormat("SELECT COUNT(1) FROM {0} WHERE {1}={2}", xs.GetTableQName(obj.TypeInfo), // 0 xs.ArrangeSqlName("ObjectID"), // 1 xs.ArrangeSqlGuid(obj.ObjectID) // 2 ); } else { // еще один объект того же типа queryTextBuilder.AppendFormat(" OR {0}={1}", xs.ArrangeSqlName("ObjectID"), // 0 xs.ArrangeSqlGuid(obj.ObjectID) // 1 ); } sTypeNamePrev = obj.ObjectType; } cmd.CommandText = queryTextBuilder.ToString(); if (Convert.ToInt32(cmd.ExecuteScalar()) > 0) { throw new XOutdatedTimestampException(); } } } return(nRowsAffected); }
public XResponse Execute(SaveObjectInternalRequest request, IXExecutionContext context) { ITUser user = (ITUser)XSecurityManager.Instance.GetCurrentUser(); ArrayList aObjects = request.DataSet.GetModifiedObjectsByType("TimeLoss", true); foreach (DomainObjectData xobj in aObjects) { if (!xobj.HasUpdatedProp("Worker") && xobj.IsNew) { xobj.SetUpdatedPropValue("Worker", user.EmployeeID); } // получим папку, проверим у папки отсутствие флага IsLocked object vValue = xobj.GetPropValue("Folder", DomainObjectDataSetWalkingStrategies.UseUpdatedPropsThanLoadedProps); DomainObjectData xobjFolder = null; if (vValue is Guid) { xobjFolder = xobj.Context.Get(context.Connection, xobj, "Folder", DomainObjectDataSetWalkingStrategies.UseUpdatedPropsThanLoadedProps, true); // проверим состояние папки. если она закрыта или в ожидании закрытия, то запретим списание if ((FolderStates)xobjFolder.GetLoadedPropValue("State") == FolderStates.Closed || (FolderStates)xobjFolder.GetLoadedPropValue("State") == FolderStates.WaitingToClose || (FolderStates)xobjFolder.GetLoadedPropValue("State") == FolderStates.Frozen) { throw new XSecurityException("Списания в папку в состоянии \"Закрыто\" или \"Ожидание закрытия\" запрещены. По вопросам списаний обращайтесь к менеджеру."); } // проверим наличие у папки специального аттрибута, запрещающего списание if ((bool)xobjFolder.GetPropValue("IsLocked", DomainObjectDataSetWalkingStrategies.UseUpdatedPropsThanLoadedProps)) { throw new XSecurityException("<b>Списания в данную папку запрещены.</b><br/>По вопросам списаний обращайтесь к менеджеру."); } FolderPrivilegeManager manager = (XSecurityManager.Instance.SecurityProvider as SecurityProvider).FolderPrivilegeManager; // у пользователя должны быть права на списание в данной папке if (!manager.HasFolderPrivilege(user, FolderPrivileges.SpentTimeByProject, xobjFolder, context.Connection)) { throw new XSecurityException("<b>Пользователь должен обладать в проекте привилегией \"Списание времение на проект\".</b><br/>По вопросам списаний обращайтесь к менеджеру."); } // если у пользователя нет привилегии «Разрешение списания на папку с неоднозначным определением направления» // проверим - является ли данная папка папкой с неоднозначным определением направления if (!manager.HasFolderPrivilege(user, FolderPrivileges.TimeLossOnUnspecifiedDirection, xobjFolder, context.Connection)) { using (XDbCommand c = context.Connection.CreateCommand()) { c.CommandType = CommandType.Text; c.CommandText = @" IF ( SELECT t.AccountRelated FROM dbo.ActivityType t WITH(NOLOCK) JOIN dbo.Folder fT WITH(NOLOCK) ON fT.ActivityType = t.ObjectID WHERE fT.ObjectID = @FolderID ) = 0 SELECT 1 ELSE SELECT TOP 1 t.DirsQnt FROM ( SELECT fU.ObjectID, fU.LRLevel, ( SELECT COUNT(*) FROM dbo.FolderDirection fd WITH(NOLOCK) WHERE fd.Folder = fU.ObjectID ) AS DirsQnt FROM dbo.Folder fT WITH(NOLOCK) JOIN dbo.Folder fU WITH(NOLOCK) ON fU.Customer = fT.Customer AND fU.LIndex <= fT.LIndex AND fU.RIndex >= fT.RIndex WHERE fT.ObjectID = @FolderID ) t WHERE DirsQnt > 0 ORDER BY LRLevel DESC "; c.Parameters.Add("FolderID", DbType.Guid, ParameterDirection.Input, false, vValue); object oResult = c.ExecuteScalar(); string sReport = null; if (null == oResult || DBNull.Value == oResult) { sReport = "для которой не определено ни одного направления"; } else if (1 != (int)oResult) { sReport = "для которой определено более одного направления"; } if (null != sReport) { throw new XSecurityException( "<b>Списания в данную папку запрещены.</b><br/>" + "У Вас нет прав списывать в папку, " + sReport + ". " + "По вопросам списаний <b>обращайтесь к менеджеру</b>."); } } } } // если в объекте заданы "виртуальные" свойства if (xobj.HasUpdatedProp("LossFixedStart") && xobj.GetUpdatedPropValue("LossFixedStart") is DateTime && xobj.HasUpdatedProp("LossFixedEnd") && xobj.GetUpdatedPropValue("LossFixedEnd") is DateTime) { if (!xobj.IsNew) { throw new ApplicationException("Задание диапазона допустимо только при создании объекта \"Списание времени\""); } // получим даты начала и окончания периода DateTime dtPeriodStart = (DateTime)xobj.GetUpdatedPropValue("LossFixedStart"); DateTime dtPeriodEnd = (DateTime)xobj.GetUpdatedPropValue("LossFixedEnd"); if (dtPeriodStart > dtPeriodEnd) { DateTime dtTemp = dtPeriodEnd; dtPeriodEnd = dtPeriodStart; dtPeriodStart = dtTemp; } Guid employeeID = (Guid)xobj.GetUpdatedPropValue("Worker"); // проверим, что в данном периоде отсутствуют списания XDbCommand cmd = context.Connection.CreateCommand(""); cmd.CommandText = @"SELECT DISTINCT CONVERT(varchar, x.SpentDate, 104) FROM ( SELECT ts.RegDate AS SpentDate FROM TimeSpent ts JOIN Task t ON ts.Task = t.ObjectID WHERE t.Worker = @EmployeeID AND ts.RegDate >= @dtPeriodStart AND ts.RegDate < @dtPeriodEnd UNION SELECT ts.LossFixed AS SpentDate FROM TimeLoss ts WHERE ts.Worker = @EmployeeID AND ts.LossFixed >= @dtPeriodStart AND ts.LossFixed < @dtPeriodEnd ) x" ; cmd.Parameters.Add("EmployeeID", DbType.Guid, ParameterDirection.Input, false, employeeID); cmd.Parameters.Add("dtPeriodStart", DbType.Date, ParameterDirection.Input, false, dtPeriodStart); // AddDays(1) - т.к. в условии запроса знак "меньше" cmd.Parameters.Add("dtPeriodEnd", DbType.Date, ParameterDirection.Input, false, dtPeriodEnd.AddDays(1)); using (IDataReader reader = cmd.ExecuteReader()) { if (reader.Read()) { StringBuilder bld = new StringBuilder(); do { if (bld.Length > 0) { bld.Append(", "); } bld.Append(reader.GetString(0)); } while(reader.Read()); throw new XBusinessLogicException( String.Format("У вас уже имеются списания на следующие даты в заданном периоде ({0},{1}): {2}", dtPeriodStart.ToShortDateString(), dtPeriodEnd.ToShortDateString(), bld.ToString()) ); } } // Получаем "набор пар" дата - норма сотрудника на дату Dictionary <DateTime, int> dictDateRates = new Dictionary <DateTime, int>(); dictDateRates = GetDayRates(context.Connection, dtPeriodStart, dtPeriodEnd, employeeID); // пойдем по всем дням периода (dtPeriodEnd, dtPeriodStart) // и для каждой даты создадим новый объект Списание времени с количеством времени равном рабочему дню // При этом, будем игнорировать даты, попадающие на выходные/праздники TimeSpan period = (dtPeriodEnd - dtPeriodStart); for (int nOffSet = 0; nOffSet <= period.TotalDays; ++nOffSet) { int nRate = 0; DateTime dtDate = dtPeriodStart.AddDays(nOffSet); // Если удалось получить норму сотрудника на соотв. дату, то создадим объект if (dictDateRates.TryGetValue(dtDate, out nRate)) { // Если полученная норма больше 0, тогда создадим списание if (nRate > 0) { DomainObjectData xobjNew = createTimeLossObject(request.DataSet, xobj, user); xobjNew.SetUpdatedPropValue("LossFixed", dtDate); // списание длиной в количество минут в рабочем дне xobjNew.SetUpdatedPropValue("LostTime", nRate); } } } // исходный объект надо удалить request.DataSet.Remove(xobj); } } XSecurityManager sec_man = XSecurityManager.Instance; IEnumerator enumerator = request.DataSet.GetModifiedObjectsEnumerator(false); DomainObjectData xobject; while (enumerator.MoveNext()) { xobject = (DomainObjectData)enumerator.Current; if (xobject.ToDelete) { sec_man.DemandDeleteObjectPrivilege(xobject); } else { sec_man.DemandSaveObjectPrivilege(xobject); } } // #1: Запись данных XStorageGateway.Save(context, request.DataSet, request.TransactionID); // Специального результата операция не возвращает return(new XResponse()); }
/// <summary> /// Формирует и выполняет явный SQL-запрос на получение значения свойства /// (столбца) ObjectID для указанного ds-типа, для экземпляра, заданного /// значениями своих параметров /// </summary> /// <param name="sRequiredTypeName"> /// Наименование ds-типа, для которого формируется запрос /// </param> /// <param name="dictionaryParams"> /// Хеш параметров; здесь в паре ключ пары - наименование параметра, /// значение пары - собственно значение параметра. Последний может быть /// типизированным значением, значением в стрковом представленнии. /// Технически допустимо значение в виде массива типизированных значений /// или их строковых представлений, но такие значения в данном случае /// неприменимы и приводят к генерации исключения ArgumentException. /// </param> /// <param name="connection">Соединение с СУБД; на момент вызова д.б. открыто</param> /// <returns>Значение ObjectID экземпляра объекта</returns> protected Guid processExplicitObjectIdRequest( string sRequiredTypeName, Hashtable dictionaryParams, XStorageConnection connection) { // SQL-операция получения значения ObjectID экземпляра заданного типа XDbCommand command = connection.CreateCommand(); // Строка, в которой будем собирать WHERE-условие для SQL-операции StringBuilder sWhereClause = new StringBuilder(); // #1: Формируем WHERE-условие; для этого перебираем все параметры, // переданные в составе коллекции, и для каждого параметра (а) добавляем // условие в WHERE-выражение, (б) добавляем соответствующий параметр в // коллекцию параметров SQL-операции. Наименование свойства, на которое // накладывается условие и наименование параметра формируются на основании // наименования парамтра, переданного в исходной коллекции; на всякий // пожарный случай к нарименованию параметра в SQL-выражении добавляем // префикс "param": foreach (DictionaryEntry item in dictionaryParams) { // В случае непосредственного запроса на получение ObjectID // массивные значения параметров недопустимы: if (item.Value is ArrayList || item.Value is Array) { throw new ArgumentException(String.Format( "В качестве значения параметра {0} передан массив значений, " + "что недопустимо в случае явного запроса идентификатора объекта типа {1}", item.Key.ToString(), sRequiredTypeName) ); } // Если значение параметра задано как NULL, то это специальный случай // условия, обрабатываем его отдельно: if (null == item.Value) { // Наименование свойства, на которое накладывается условие, // есть наименования параметра, переданного в коллекции: sWhereClause.AppendFormat( "(obj.{0} IS NULL) AND ", connection.Behavior.ArrangeSqlName(item.Key.ToString()) ); } else { // Наименование SQL-параметра: наименование параметра из // в исходной коллекции, к которому добавлен префикс: string sParamName = "param" + item.Key.ToString(); // Наименование свойства, на которое накладывается условие, // есть наименования параметра из исходной коллекции: sWhereClause.AppendFormat("(obj.{0}={1}{2}) AND ", connection.Behavior.ArrangeSqlName(item.Key.ToString()), // 0 connection.Behavior.ParameterPrefix, // 1 sParamName // 2 ); // Создаем объект-параметр, добавлем его в коллекцию параметров // SQL-операции: XDbParameter param = command.CreateParameter(); param.ParameterName = sParamName; param.VarType = XPropTypeParser.GetNearestTypeForCLR(item.Value.GetType()); param.Value = item.Value; // Если тип параметра есть строка - ограничим размерность, // т.к. в противном случае это будет максимальная размерность - 4К - // и будет достаточно заметно тормозить. В качестве исходной размерности // укажем длину реально заданного значения, увеличенного на 2: if (item.Value is string) { param.Size = ((string)item.Value).Length + 2; } command.Parameters.Add(param); } } sWhereClause.Append("(1=1)"); // #2: Формируем и выполняем полную SQL-операцию command.CommandType = System.Data.CommandType.Text; command.CommandText = String.Format( "SELECT TOP 1 obj.ObjectID FROM {0} obj WHERE {1}", connection.GetTableQName(sRequiredTypeName), sWhereClause.ToString() ); object oResult = command.ExecuteScalar(); // #3: Ожидается, что в результате мы получаем GUID; если // результата нет вообще, возвращаем Guid.Empty; Guid uidResult = Guid.Empty; if (null != oResult && DBNull.Value != oResult) { uidResult = connection.Behavior.CastGuidValueFromDB(oResult); } return(uidResult); }