Очень часто хочется создать из ничего объект, сохранить его на сервере и стразу же получить с сервера все автоматически генерируемые поля. Например, identities.
Примерно вот так:
Person p = new Person("John", "Pupkin");
SomeMagicToInsertIntoTablePerson(p);
// Вот здесь p.ID уже имеет осмысленное и готовое к употреблению значение.
На низком уровне всё просто. Можно, например написать вот такую хранимую процедуру (MsSql):
CREATE Procedure Person_Insert
@FirstName nvarchar(50),
@LastName nvarchar(50),
@MiddleName nvarchar(50),
@Gender char(1)
AS
INSERT INTO Person
( LastName, FirstName, MiddleName, Gender)
VALUES
(@LastName, @FirstName, @MiddleName, @Gender)
SELECT Cast(SCOPE_IDENTITY() as int) PersonID
и вызывать её таким вот образом:
using (DbManager db = new DbManager())
{
db
.SetSpCommand("Person_Insert", db.CreateParameters(e))
.ExecuteObject(e);
}
Т.е. с объекта типа Person создаются параметры, вызывается хранимая процедура, а возвращаемые поля (в данном случае PersonID) автоматически мапятся на тот же самый объект. Этот подход хорош тем, что в таком виде хранимую процедуру можно легко заменить на простой запрос и использовать с базой данных не поддерживающей хранимые проуедуры (Access, SqlCe).
А можно воспользоваться возвращаемыми параметрами (Oracle):
CREATE OR REPLACE
PROCEDURE Person_Insert
( pFirstName IN NVARCHAR2
, pLastName IN NVARCHAR2
, pMiddleName IN NVARCHAR2
, pGender IN CHAR
, pPersonID OUT NUMBER
) IS
BEGIN
INSERT INTO Person
( LastName, FirstName, MiddleName, Gender)
VALUES
(pLastName, pFirstName, pMiddleName, pGender)
RETURNING
PersonID
INTO
pPersonID;
END;
и вызывать её вот таким образом:
using (DbManager db = new DbManager())
{
db
.SetSpCommand("Person_Insert", db.CreateParameters(e, new string[]{"PersonID"}, null))
.ExecuteNonQuery();
db.MapOutputParameters(e);
}
И это будет выполняться гораздо быстрее, чем предыдущий способ, так как параметры уже вернулись с сервера на выходе из ExecuteNonQuery, а чтение из DataReader'а в предыдущем примере требует ещё одного обращения к серверу. Кроме того,
инициализация чтения из DataReader'а в BLToolkit'е довольно сложная процедура, в то время как чтение значения из IDbDataParameter'а это простейшая операция.
Кроме того, есть ещё один, немного экзотический вариант. Если возвращается ровно одно значение, то его можно вернуть из хранимой процедуры в качестве RETURN_VALUE (MsSql):
CREATE FUNCTION Person_Insert
@FirstName nvarchar(50),
@LastName nvarchar(50),
@MiddleName nvarchar(50),
@Gender char(1)
RETURNS int
AS
INSERT INTO Person
( LastName, FirstName, MiddleName, Gender)
VALUES
(@LastName, @FirstName, @MiddleName, @Gender)
RETURN Cast(SCOPE_IDENTITY() as int)
В этом случае использовать это можно так:
using (DbManager db = new DbManager())
{
db
.SetSpCommand("Person_Insert", db.CreateParameters(e))
.ExecuteNonQuery();
db.MapOutputParameters(e, "PersonID");
}
Отличия от предыдущего варианта исключительно косметические.
А здесь все весьма неочевидно. Если для DataAccessorBuider можно будет реализовать все эти варианты, введя нужное количество атрибутов, то в самом DataAccessor'е для CRUDL операций нужно что-то одно. Либо реализовывать их всех с разными суффиксами. Вобщем, полный

... << RSDN@Home 1.2.0 alpha rev. 642>>