Коллеги, приветствую.

Есть некоторый запрос к базе данных, полученный с использованием класса SELECT (считывается информация о платежах за период по ФИО должника.):

var selectPaymentsRegister = (Select)new Select(userConnection)
        .Column("c", "Surname").As("Surname")
        .Column("c", "GivenName").As("Name")
        .Column("c", "MiddleName").As("MiddleName")
        .Column("c", "Name").As("FullName")
        .Column("c", "Phone").As("Phone")
        .Column("c", "Address").As("Address")
        .Column("up", "UsrPaymentSum").As("Amount")
        .Column("up", "UsrPaymentDate").As("AmountDate")
        .From("UsrPayments").As("up")
        .Join(JoinType.Inner, "Contact").As("c")
        .On("up", "UsrDebtorId").IsEqual("c", "Id")
        .Where("c", "Surname").IsEqual(Column.Parameter(debtorSurname))
        .And("c", "GivenName").IsEqual(Column.Parameter(debtorName))
        .And("c", "MiddleName").IsEqual(Column.Parameter(debtorMiddleName))
        .And("up", "UsrPaymentDate").IsGreaterOrEqual(Column.Parameter(dateBegin))
        .And("up", "UsrPaymentDate").IsLessOrEqual(Column.Parameter(dateEnd))

        as Select;

Далее, с использованием IDataReader в цикле я получаю значения полей.

Как составить такой же запрос, но с использованием EntitySchemaQuery? Хочу подробнее разобраться в этой теме.

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

Нравится

2 комментария

Коллеги, приветствую.

Есть определенный интерес поизучать классы Select, Insert, Update, EntitySchemaQuery и подробнее
разобраться, как с ними работать.

Чтобы это было проще и быстрее мне бы хотелось иметь возможность работать с ними из MS Visual Studio.

Например, запрос из статьи Использование EntitySchemaQuery для построения запросов к базе данных:

// Создание экземпляра запроса, добавление в запрос колонок и источника данных.
Select selectQuery = new Select(UserConnection)
                    .Column("Id")
                    .Column("Name")
                    .From("Contact");
// Выполнение запроса к базе данных и получение результирующего набора данных.
using (DBExecutor dbExecutor = UserConnection.EnsureDBConnection())
{
    using (IDataReader reader = selectQuery.ExecuteReader(dbExecutor))
    {
        while (reader.Read())
        {
            // Обработка результатов запроса.
        }
    }
}

Собственно, вопрос в конфигурировании класса UserConnection, как его использовать "вне платформы", не в режиме отладки?

Например, в методе Main:

static void Main(string[] args)
{
}

В элементе "Задание- сценарий" я могу получить его таким образом:

var userConnection = Get("UserConnection");

В Web- сервисе WCF:

var userConnection = (UserConnection)HttpContext.Current.Session["UserConnection"];

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

Нравится

2 комментария

Здравствуйте.
Если сайт у вас развернуть on-site, то есть, поднят на своем IIS сервере:
Тогда у вас есть возможность написать свой, к примеру, веб-сервис, или даже скрипт-сценарий, и пользуясь статьей по отладке,
http://academy.terrasoft.ru/documents/docs/technic/SDK/7.6.0/ServerCode…
ставить точки останова, и изучать поведение серверного ESQ.
Здесь главное, что бы код был частью системы, поэтому его и нужно писать как часть системы (веб-сервис, бизнес-процесс, и.т.д.), а не сторонние dll,exe,итд.
С автономной программы этого сделать не получится.

Если же сайт on-demand, то есть, развернут как http://имя-сайта.bpmonline.com/
То такой возможности у Вас нет, и со стороннего процесса (программы), Вы никак не обратитесь к ядру системы.
Из сторонних программ написанных Вами в Visual Studio, Вы можете разве что обратится к уже написанным веб-сервисам в рамках структуры сайта, либо же по протоколу OData,
http://academy.terrasoft.ua/documents/docs/technic/SDK/7.4.1/WorkWithBp… что, конечно же, совсем не запросы ESQ.

Александр, спасибо большое за ответ!

Показать все комментарии

Коллеги, приветствую.

Есть некоторый запрос, который возвращает дату платежа и дату последней активности по платежу:

SELECT
        ContactId AS debtorId,
        t1.CreatedOn AS activityDate,
        t2.CreatedOn AS paymentDate
FROM Activity AS t1 INNER JOIN UsrPayments AS t2
        ON t1.ContactId = t2.UsrDebtorId
WHERE t1.CreatedOn = (
        SELECT max(CreatedOn) FROM Activity
        WHERE t1.ContactId = t2.UsrDebtorId
);

И есть некоторый код C#, где с помощью подзапроса я хочу определить дату последней активности по платежу, аналогично тому, как я это делаю выше на native SQL:

var selectNewPayments = (Select)new Select(userConnection)
        .Column("t1", "ContactId")
        .Column("t1", "CreatedOn")
        .Column("t2", "CreatedOn")
        .From("Activity").As("t1")
        .Join(JoinType.Inner, "UsrPayments").As("t2")
        .On("t1", "ContactId").IsEqual("t2", "UsrDebtorId")
        .Where("... здесь подзапрос и обращение к функции max() ...")
        as Select;

Как этот подзапрос написать?

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

Нравится

5 комментариев

Здравствуйте!
Все функции описаны по ссылке.

Пример:

SELECT 
C.Name,
(SELECT COUNT(*) FROM Activity A WHERE A.ContactId = C.Id) As ActivityCount
FROM Contact C

Перевод в С#:

var subSelect = new Select(userConnection)
                .Column(Func.Count(Column.Asterisk()))
.From("Activity").As("A")
.Where("C", "Id").IsEqual("A", "ContactId").As("ActivityCount")
var select = new Select(userConnection)
                .Column("C", "Name")
                .Column(subSelect)
.From("Contact").As("C")

Супер! Алексей, спасибо большое.

А можно то же самое, только не Select'ом а с помощью ESQ?

Здравствуйте, Олег!

Примеры доступны по ссылке:
https://www.terrasoft.ru/bpmonlinesdk/UsingEntitySchemaQuery.html

"Шамшин_Олег" написал:А можно то же самое, только не Select'ом а с помощью ESQ?

1. Делаете один esq запрос на содержимое подзапроса, выбираете из него, список Id, или чего вам нужно, в оригинальном посте подзапрос выбирал CreatedOn. Формируете массив этих CreatedOn.

2. В колбеке после возврата результата подзапроса, формируете новый esq запрос, с фильтрацией нужной колонки, в оригинальном посте CreatedOn на вхождение в массив ранее выбранных CreatedOn.

Т.к. фильтрация createColumnInFilterWithParameters спокойно проверит вхождение колонки и в массив.
Пример оторванный от контекста esq, рассматривает только создания фильтра, но такой фильтр подставленный в esq будет работать и в esq:
http://www.community.terrasoft.ru/forum/topic/11497#comment-50859

Показать все комментарии

Коллеги, приветствую.

Есть некоторый запрос, который возвращает информацию по должнику и последней активности, проявленной в отношении него:

SELECT
        TOP 1  
        ContactId as id,
        AC.CreatedOn as activityDate,
        UP.CreatedOn as paymentDate

FROM
        Activity as AC INNER JOIN UsrPayments as UP
                ON AC.ContactId = UP.UsrDebtorId
WHERE
        UP.CreatedOn  > AC.CreatedOn

ORDER BY AC.id ASC;

И есть некоторый код на C#, где с помощью класса Select проделывается то же, но считываются записи по всем активностям:

var selectNewPayments = (Select)new Select(userConnection)
                .Column("t1", "ContactId")
                .Column("t1", "CreatedOn")
                .Column("t2", "CreatedOn")
                .From("Activity").As("t1")
                .Join(JoinType.Inner, "UsrPayments").As("t2")
                .On("t1", "ContactId").IsEqual("t2", "UsrDebtorId")
                .Where("t1", "CreatedOn")
                .IsLess("t2", "CreatedOn") as Select;

Как прочитать только первую запись?

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

Нравится

2 комментария

Нашел, собственно -

var selectNewPayments = (Select)new Select(userConnection)
   .Top(1)
   .Column("t1", "ContactId") 
   .Column("t1", "CreatedOn")
   .Column("t2", "CreatedOn")
   .From("Activity").As("t1")
   .Join(JoinType.Inner, "UsrPayments").As("t2")
   .On("t1", "ContactId").IsEqual("t2", "UsrDebtorId")
   .Where("t1", "CreatedOn").IsLess("t2", "CreatedOn").OrderByAsc("t1", "id") as Select;

Такой запрос возможен???

select count(ID)

   from [dbo].[Case] AS TI

WHERE DATEPART(HOUR, DATEADD(hh, 6, TI.[UsrDueDate])) >=9  and DATEPART(HOUR, DATEADD(hh, 6, TI.[UsrDueDate])) <12

and FORMAT(DATEADD(hh, 6, TI.[UsrDueDate]), N'yyyy.MM.dd') = FORMAT(cast(GETDATE() +1 as date), N'yyyy.MM.dd')

Показать все комментарии

Здравствуйте, изучил тему по ссылке. В частности последний пост.
Возник ряд вопросов:
- Как правильно использовать dbExecutor для избежания утечки памяти?
- В каких именно случаях нужно пользоваться указанным в теме подходом?
- Всегда ли нужно оборачивать методы Execute() и ExecuteScalar() классов Select, Insert, Update в using, если нет, то в каких случаях это не обязательно?

Используемые версии приложения - от 7.4 и выше

Нравится

5 комментариев

продублирую пост из ссылки в данную тему:

"Венжик Игорь" написал:Часто возникает ситуация когда необходимо сделать специфичечкий запрос к БД, который невозможно или сложно воспроизвести с помощью бизнес-сущностей. Например запросы к таблицам прав доступа, к системным таблицам. (Не законченная статья...)

В таких случая необходимо строить кастомные запросы:

Select select =
        new Select(UserConnection)
                .Column("Id")
                .Column("SysSchemaId")
                .Column("Name")
                .Column("SysSchemaManagerName")
                .Column("SysSchemaFolderId")
                .Column("MetaDataModifiedOn")
        .From("VwSysSchemaInSolution")
        .Where("SysSolutionId").IsEqual(new QueryParameter("solutionId", userConnection.Solution.Id))
                .And("SysSchemaId").In(schemas)
                .And("SysSchemaStateInSolution").IsNotEqual(Column.Const((int)StoringObjectState.Deleted))
                .And().OpenBlock("LockedById").IsNull()
                        .Or("LockedById").IsEqual(new QueryParameter("currentUserId", userConnection.CurrentUser.Id))
                .CloseBlock()
                as Select;
Для выполнения запросов к БД в нашей системе есть специальный объект DBExecutor. Экземпляр которого содержится в каждом UserConnection-е. То есть одному пользователю всегда доступен только один экземпляр DBExecutor-а, и пользователь не может сам создавать новые экземпляры.
Что бы получить экземпляр DBExecutor-а необходимо вызвать метод UserConnection.EnsureDBConnection().
using (var dbExecutor = UserConnection.EnsureDBConnection()) {

}
Для вызова всегда необходимо использовать конструкцию using!

Давайте раcсмотрим несколько вариантов работы

Допустим нам необходимо выполнить простой запрос:

Select select =
        new Select(UserConnection)
                .Column("Name")
        .From("Contact")
        .Where("City").IsEqual(Column.Parameter("Киев"))

Получение значения из первой строки, первого столбца выборки

Есть два способа

var name = select.ExecuteScalar();
или
string name;
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
        name = select.ExecuteScalar(dbExecutor);
}
Оба способа вернут один и тот же результат. Если вы выполняете одиночный запрос тогда используйте первый вариант, он является оберткой над вторым. Второй вариант, с передачей dbExecutor-а, будет полезен если выполнять несколько запросов к БД в рамках одной транзакции.

Получение списка значений:

List names = new List();
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
        using (var reader = select.ExecuteReader(dbExecutor)) {
                while(reader.Read()) {
                        int columnOrdinal = reader.GetOrdinal("Name");
                        names.Add(reader.GetString(columnOrdinal));
                }
        }
}

Выполнение запроса в рамках транзакции:

Оба запроса в базу будут выполнены в рамках транзакции и в случае свала транзакция откатится.

List names = new List();
using (var dbExecutor = UserConnection.EnsureDBConnection()) {

>>      dbExecutor.StartTransaction();
       
        using (var reader = select.ExecuteReader(dbExecutor)) {
                while(reader.Read()) {
                        int columnOrdinal = reader.GetOrdinal("Name");
                        names.Add(reader.GetString(columnOrdinal));
                }
        }
        insert.Execute(dbExecutor);

>>      dbExecutor.CommitTransaction();

}
Транзакция начинается вызовом метода dbExecutor.StartTransaction и заканчивается вызовом CommitTransaction или RollbackTransaction. В случае когда выполнение вышло за область видимости блока using и CommitTransaction не был вызван, происходит автоматический откат транзакции. Таким образом нет необходимости оборачивать транзакцию в try/catch блок, т.к. если был свал во время выполнения транзакция автоматически откатится.

Внимание! В текущей реализации даже если не передавать dbExecutor в метод Execute(), все равно запрос будет выполнен в текущей транзакции, если такая существует. Но для избежания сложностей в будущем, всегда при выполнении нескольких запросов в рамках транзакций - всегда передавайте dbExecutor в методы Execute, ExecuteReader, ExecuteScalar.

Здравствуйте!

Методы Execute() и ExecuteScalar() классов Select, Insert, Update в using оборачивать не нужно.
Для Select-ов ExecuteScalar или Execute, который принимает анонимный метод - также не стоит оборачивать в using.
Для Select-а, который использует конструкцию List names необходимо использовать Using:

List names = new List();
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
using (var reader = select.ExecuteReader(dbExecutor)) {
while(reader.Read()) {
int columnOrdinal = reader.GetOrdinal("Name");
names.Add(reader.GetString(columnOrdinal));
}
}
}

Добрый день! Давно и сильно интересует вопрос, каким образом обернуть в транзакцию событийный процесс объекта при сохранении/удалении? Для гарантированной согласованности данных в разных сущностях, когда изменения в одном объекте влекут изменения в другом связанном.

Показать все комментарии

Коллеги, приветствую.

Столкнулся с некоторыми трудностями чтения из базы данных с помощью объекта DBExecutor.

Есть простой кастомный запрос:

 

var userConnection = Get("UserConnection");
Guid addedRecordId = Get("addedRecordId");

var selectQuery = new Select(userConnection)
        .Column("UsrName")
        .From("UsrDebt").As("ud")
        .Where("UD", "Id")
                .IsEqual(Column.Parameter(addedRecordId));

 

Читаю значение UsrName (пример - Помогите с запросом):

 

using (var dbExecutor = userConnection.EnsureDBConnection()) {
        var name = selectQuery.ExecuteScalar(dbExecutor); // строка 46
}

 

Получаю ошибку компиляции -

Если читаю набор данных, как показано в статье Использование EntitySchemaQuery для построения запросов к базе данных:

 

var userConnection = Get("UserConnection");
Guid addedRecordId = Get("addedRecordId");

var selectQuery =
        new Select(userConnection)
        .Column("UsrName")
        .From("UsrDebt").As("ud")
        .Where("UD", "Id")
                .IsEqual(Column.Parameter(addedRecordId));

// Выполнение запроса к базе данных и получение результирующего набора данных.
using (DBExecutor dbExecutor = userConnection.EnsureDBConnection())
{
    using (IDataReader reader = selectQuery.ExecuteReader(dbExecutor)) // строка 48
    {
        while (reader.Read())
        {
            // Обработка результатов запроса.
        }
    }
}

 

Получаю такую ошибку:

Как я могу получить значения из базы данных с помощью объекта DBExecutor?

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

Нравится

1 комментарий

Добавил преобразование к типу Select, теперь все Ок.

var selectQuery = new Select(userConnection)
    	.Column("UsrName")
    	.From("UsrDebt").As("ud")
    	.Where("UD", "Id")
	.IsEqual(Column.Parameter(addedRecordId)) as Select;
Показать все комментарии

Коллеги, приветствую.

Есть некоторый простой бизнес- процесс, инициируемый событием- сигналом "Добавление записи в таблицу". При каждом добавлении записи я получаю ее уникальный идентификатор, например -

F6F4725A-C7C6-4AA2-BE50-E4878ACB7D4B

Я выполняю простой запрос из MS SQL Server Management Studio -

SELECT
        UsrInDebtId
FROM
        UsrDebt
WHERE
        Id='F6F4725A-C7C6-4AA2-BE50-E4878ACB7D4B';

Получаю какой- то результат.

Аналогично из кода C#

...
myConnection.Open();
SqlCommand myCommand = new SqlCommand("...", myConnection);
SqlDataReader myReader = myCommand.ExecuteReader();
while (myReader.Read()) {
   ...
}
...    

Уникальный идентификатор я сохраняю в параметре addedRecordId -

Guid addedRecordId = Get("addedRecordId");

Далее я хочу использовать класс Select из пространства имен Terrasoft.Core.DB -

var userConnection = Get("UserConnection");
Select select = (Select)new Select(userConnection)
            .Column("UserInDebtId")
            .From("UsrDebt").As("UD")
            .Where("UD", "Id")
            .IsEqual(addedRecordId); // строка 42

Получаю ошибки компиляции -

Как я могу использовать Guid в условии IsEqual?

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

Нравится

6 комментариев

Может быть, существует возможность получить строковое представление уникального идентификатора из события- сигнала и далее уже программно создать Guid, который и передать в предикат?..

Например:

string str = "F6F4725A-C7C6-4AA2-BE50-E4878ACB7D4B";
Guid guid = new Guid(str);

А затем уже:

...
.IsEqual(guid);

Хотя и не совсем ясно, что бы это могло дать...

Алексей,

В этом случае можно решить задачу двумя способами:

Вариант 1.
.IsEqual(addedRecordId.ToString());
Вариант 2.
.IsEqual(Column.Parameter(addedRecordId));

Второй вариант более корректный.

Здравствуйте, Олег! Большое спасибо за ответ, попробую сегодня.

В обоих случаях получаю такую ошибку компиляции:

Cannot implicity convert type 'Terrasoft.Core.DB.Query' to 'Terrasoft.Core.DB.Select'. An explicit
conversion exists (are you missing a cast?)

Нужно видеть всю картину, трудно так определить где зарыт камень.
Напишите в техническую поддержку.

Олег, спасибо.

Помогло использование переменной с неявным типом:

var selectQuery = 
	new Select(userConnection) ...
Показать все комментарии

Добрый день, коллеги!

Имеется примерно такой запрос:

var newSelect = new Select(CurrentUserConnection)
        .Column("Table1", "Column1").As("Column1")
        .From("Table1").As("Table1")
        .Where("Table1", "Column2").IsNotEqual(  ...  ) as Select;

И имеется некоторая коллекция значений, к примеру:

List myList = new List();

Вопрос в следующем: Каким образом можно в условие запроса передать список значений моей коллекции (будь то Array, ArrayList, List, Dictionary, Hashtable, SortedList или другое - значения не имеет)?

Условно говоря, мне нужно мою коллекцию представить в виде типа "Select", чтобы можно было использовать в месте отмеченном 3-мя точками, - это если следовать сигнатуре этих методов, согласно описанию из SDK (www.terrasoft.ru/bpmonlinesdk/). Но как это сделать? Прошу помощи!

Нравится

5 комментариев

Виталий, для этого нужно использовать конструкцию .Not().In(массив_или_список_идентификаторов) .
Пример использования (схема EditSynchUserInSynchRole):

var ldapGroupsIds = new List<QueryParameter>();
	var ldapUserLoginAttribute = SysSettings.GetValue(UserConnection, "LDAPUserLoginAttribute").ToString();
	using (var ldapUtils = new LdapUtilities(UserConnection)) {
		var usersCollection = ldapUtils.GetUsersAttributesByFilter(ldapUserLoginAttribute + "=" + ldapEntry, new [] {"distinguishedName"});
		var userDn = string.Empty;
		foreach (SearchResultEntry user in usersCollection) {
			userDn = user.DistinguishedName;
			break;
		}
		var ldapGroupIdentityAttribute = SysSettings.GetValue(UserConnection, "LDAPGroupIdentityAttribute").ToString();
		var groupsCollection = ldapUtils.GetGroupsAttributesByFilter("member=" + userDn, new [] {ldapGroupIdentityAttribute});
		foreach(SearchResultEntry group in groupsCollection) {
			ldapGroupsIds.Add(new QueryParameter(ldapUtils.IdentityAttributeToString(group.Attributes[ldapGroupIdentityAttribute][0])));
		}
	}
 
	if (ldapGroupsIds.Count < 1) {
		return true;
	}
 
	var delete = new Delete(UserConnection).From("SysUserInRole").
	Where("SysUserId").IsEqual(Column.Parameter(userId)).
	And().Exists(new Select(UserConnection).
		Column("Id").From("SysAdminUnit").
		Where("SysUserInRole", "SysRoleId").IsEqual("SysAdminUnit", "Id").
		And("SynchronizeWithLDAP").IsEqual(Column.Parameter(true)).
		And("LDAPEntryId").Not().In(ldapGroupsIds));
	delete.Execute();

Если же передавать массив, то так (схема AdministrativeGrantedRightsGridPage):

	object[] objectParameters = new object[adminUnitCollection.Count];
	for (int i = 0; i < adminUnitCollection.Count; i++) {
		objectParameters[i] = adminUnitCollection[i];
	}
}
var entitySchemaManager = Page.UserConnection.EntitySchemaManager;
var rightsSchema = entitySchemaManager.GetInstanceByName("SysAdminUnitGrantedRight");
var select = new Select(Page.UserConnection)
		.Column(rightsSchema.Name, "Id")
		.Column(rightsSchema.Name, "GrantorSysAdminUnitId")
		.Column("Grantor", "Name").As("GrantorSysAdminUnitName")
	.From(rightsSchema.Name)
	.InnerJoin("SysAdminUnit").As("Grantor").On("Grantor", "Id").IsEqual(rightsSchema.Name, "GrantorSysAdminUnitId")
	.Where(rightsSchema.Name, "GranteeSysAdminUnitId").In(Column.Parameters(objectParameters))
	.OrderByAsc("Grantor", "Name") as Select;

Хм... Честно говоря, если судить по информации из SDK (http://i.piccy.info/i9/fa961117bdc660b65920ae24393d4c3e/1452507140/1535…), то оператор "In()" не принимает произвольную коллекцию, потому и решил переспросить. Во всяком случае, вопрос закрыт. В очередной раз спасибо Вам, Александр!

Я тоже думал, что только массивы из Object, но оказалось, что не только массивы.
В первом примере обратите внимание, что коллекция из элементов именно типа QueryParameter.

А это действительно важно, использовать именно тип "QueryParameter"? Т.е., к примеру:

List<Guid> guids = new List<Guid>();

нельзя использовать? Или тот же тип "string"? В том же SDK есть только такой пример: http://i.piccy.info/i9/7c65675471d92405256ab8d1e300693f/1452512386/1789…

Если следовать этому описанию, то коллекция ГУИДов должна выглядеть так:

List<QueryParameter> guids = new List<QueryParameter>();
guids.Add(new QueryParameter((new Guid("...")).ToString()))

Верно ли это? Тогда я не смогу указать оператор "In()" для колонки, содержащую тип "Guid", т.к. я буду проверять наличие текущей записи в коллекции guids, а у нее QueryParameter содержит тип "string". Что-то тут нечисто... Подскажете, как быть?:confused:

Попробуйте сделать как в моём первом примере, там как раз сравнивается со списком из Guid, хоть и приводится к строке.

Показать все комментарии

Підкажіть, будь-ласка, як для Select() вписати With (Nolock)

Нравится

2 комментария

Как-то так:

var countSelect = new Select(UserConnection)
			  	.Column(Func.Count(Column.Asterisk())).As("Count") as Select;
countSelect.WithHints(Hints.NoLock);

Дякую, те, що треба :)

Показать все комментарии

Как сконструировать условие OR в Select`е? Есть запрос на TSQL:

SELECT *
FROM
[dbo].[WorkUnitAction]
WHERE
[WorkUnitId] = @p1
AND [Id] > @p2
AND [CreatedOn] @p3
AND NOT [ActionResultId] IS NULL
AND ([GroupId] > @p4 OR GroupId IS NULL)
ORDER BY
[CreatedOn] DESC

нужно его написать на шарпе..

Нравится

3 комментария

Как-то так:

...
                .And().OpenBlock("GroupId").IsNotEqual(Column.Parameter(p4))
                        .Or("GroupId").IsNull()
                .CloseBlock()
...

Тут больше по теме.

"Зверев Александр" написал:
Тут больше по теме.

За пример спасибо! А ссылка не открывается, почему-то "У Вас нет доступа к этой странице"(

Алексей, цитирую ту самую страницу.

"Венжик Игорь" написал:

Часто возникает ситуация когда необходимо сделать специфичечкий запрос к БД, который невозможно или сложно воспроизвести с помощью бизнес-сущностей. Например запросы к таблицам прав доступа, к системным таблицам. (Не законченная статья...)

В таких случая необходимо строить кастомные запросы:

Select select =

        new Select(UserConnection)

                .Column("Id")

                .Column("SysSchemaId")

                .Column("Name")

                .Column("SysSchemaManagerName")

                .Column("SysSchemaFolderId")

                .Column("MetaDataModifiedOn")

        .From("VwSysSchemaInSolution")

        .Where("SysSolutionId").IsEqual(new QueryParameter("solutionId", userConnection.Solution.Id))

                .And("SysSchemaId").In(schemas)

                .And("SysSchemaStateInSolution").IsNotEqual(Column.Const((int)StoringObjectState.Deleted))

                .And().OpenBlock("LockedById").IsNull()

                        .Or("LockedById").IsEqual(new QueryParameter("currentUserId", userConnection.CurrentUser.Id))

                .CloseBlock()

                as Select;

Для выполнения запросов к БД в нашей системе есть специальный объект DBExecutor. Экземпляр которого содержится в каждом UserConnection-е. То есть одному пользователю всегда доступен только один экземпляр DBExecutor-а, и пользователь не может сам создавать новые экземпляры.

Что бы получить экземпляр DBExecutor-а необходимо вызвать метод UserConnection.EnsureDBConnection().

using (var dbExecutor = UserConnection.EnsureDBConnection()) {



}

Для вызова всегда необходимо использовать конструкцию using!

Давайте раcсмотрим несколько вариантов работы

Допустим нам необходимо выполнить простой запрос:

Select select =

        new Select(UserConnection)

                .Column("Name")

        .From("Contact")

        .Where("City").IsEqual(Column.Parameter("Киев"))

  1. Получение значения из первой строки, первого столбца выборки

    Есть два способа

    var name = select.ExecuteScalar<string>();

    или

    string name;

    using (var dbExecutor = UserConnection.EnsureDBConnection()) {

            name = select.ExecuteScalar<string>(dbExecutor);

    }

    Оба способа вернут один и тот же результат. Если вы выполняете одиночный запрос тогда используйте первый вариант, он является оберткой над вторым. Второй вариант, с передачей dbExecutor-а, будет полезен если выполнять несколько запросов к БД в рамках одной транзакции.

  2. Получение списка значений:

    List<string> names = new List<string>();

    using (var dbExecutor = UserConnection.EnsureDBConnection()) {

            using (var reader = select.ExecuteReader(dbExecutor)) {

                    while(reader.Read()) {

                            int columnOrdinal = reader.GetOrdinal("Name");

                            names.Add(reader.GetString(columnOrdinal));

                    }

            }

    }

  3. Выполнение запроса в рамках транзакции:

    Оба запроса в базу будут выполнены в рамках транзакции и в случае свала транзакция откатится.

    List<string> names = new List<string>();

    using (var dbExecutor = UserConnection.EnsureDBConnection()) {



    >>      dbExecutor.StartTransaction();

           

            using (var reader = select.ExecuteReader(dbExecutor)) {

                    while(reader.Read()) {

                            int columnOrdinal = reader.GetOrdinal("Name");

                            names.Add(reader.GetString(columnOrdinal));

                    }

            }

            insert.Execute(dbExecutor);



    >>      dbExecutor.CommitTransaction();



    }

    Транзакция начинается вызовом метода dbExecutor.StartTransaction и заканчивается вызовом CommitTransaction или RollbackTransaction. В случае когда выполнение вышло за область видимости блока using и CommitTransaction не был вызван, происходит автоматический откат транзакции. Таким образом нет необходимости оборачивать транзакцию в try/catch блок, т.к. если был свал во время выполнения транзакция автоматически откатится.

    Внимание! В текущей реализации даже если не передавать dbExecutor в метод Execute(), все равно запрос будет выполнен в текущей транзакции, если такая существует. Но для избежания сложностей в будущем, всегда при выполнении нескольких запросов в рамках транзакций - всегда передавайте dbExecutor в методы Execute, ExecuteReader, ExecuteScalar.

Подписаться на обновления этого материала

Показать все комментарии