-
Notifications
You must be signed in to change notification settings - Fork 0
Commands
romagny13 edited this page Jul 26, 2019
·
21 revisions
Command creation
- CreateSqlCommand
- CreateStoredProcedureCommand
- CreateCommand
DbCommand extensions methods (allow to chain registration)
- AddInParameter
- AddOutParameter
- AddParameter
Execution
- SelectAllAsync returns a list of Models
- SelectOneAsync returns a Model
- InsertAsync returns the new Id (for model with primary key auto incremented for example) or the number of rows affected
- UpdateAsync returns the number of rows affected
- DeleteAsync returns the number of rows affected
- CountAsync returns a number
- ExecuteScalarAsync returns an object
- ExecuteNonQueryAsync returns the number of rows affected
Transactions
- ExecutePendingOperationsAsync
- ExecuteTransactionFactoryAsync
Best practice use Factories
- ISelectionAllCommandFactory
- ISelectionOneCommandFactory
- IInsertCommandFactory
- IUpdateCommandFactory
- IDeleteCommandFactory
- TransactionFactory
- IModelFactory
Plus
- DeepClone allows to clone object and preserve original values for example
var db = new EasyDb();
db.SetConnectionStringSettings(Constants.ConnectionString, Constants.ProviderName);
db.DefaultMappingBehavior = DefaultMappingBehavior.CreateEmptyTable;
// arguments:
// - limit
// - condition
// - sorts
var result = await db.SelectAllAsync<User>(10, Check.Op("Age", ">", 18), new string[] { "UserName DESC" });
Or with a command
var db = new EasyDb();
db.SetConnectionStringSettings(Constants.ConnectionString, Constants.ProviderName);
db.SetTable<User>("users")
.SetPrimaryKeyColumn("id", p => p.Id);
using (var command = db.CreateSqlCommand("select * from [users]"))
{
var users = await db.SelectAllAsync<User>(command);
}
Or with factories
- Command factory
public class UserSelectionAllCommandFactory : ISelectionAllCommandFactory<User, NullCriteria>
{
public DbCommand CreateCommand(EasyDb db, NullCriteria criteria)
{
return db.CreateSqlCommand("select * from [User]");
}
}
Note: Criteria allows to pass a value (a filter, a key, etc.) or a class
- Model factory (data reader => model)
public class UserModelFactory : IModelFactory<User>
{
public User CreateModel(IDataReader reader, EasyDb db)
{
return new User
{
UserName = ((string)reader["UserName"]).Trim(),
Email = reader["Email"] == DBNull.Value ? default(string) : ((string)reader["Email"]).Trim(),
Age = reader["Age"] == DBNull.Value ? default(int?) : (int)reader["Age"]
};
}
}
Or with CheckDBNullAndConvertTo function
public class UserModelFactory : IModelFactory<User>
{
public User CreateModel(IDataReader reader, EasyDb db)
{
return new User
{
UserName = ((string)reader["UserName"]).Trim(),
Email = db.CheckDBNullAndConvertTo<string>(reader["Email"])?.Trim(),
Age = db.CheckDBNullAndConvertTo<int?>(reader["Age"])
};
}
}
Execution
var db = new EasyDb();
db.SetConnectionStringSettings(Constants.ConnectionString, Constants.ProviderName);
db.DefaultMappingBehavior = DefaultMappingBehavior.CreateEmptyTable;
var result = await db.SelectAllAsync<User>(new UserSelectionAllFactory(), new UserModelFactory());
Example:
var db = new EasyDb();
db.SetConnectionStringSettings(Constants.ConnectionString, Constants.ProviderName);
db.DefaultMappingBehavior = DefaultMappingBehavior.CreateEmptyTable;
Post result = null;
using (var command = db.CreateSqlCommand("select a.Title, a.Content, a.UserId, b.UserName from [Post] as a,[User] as b where a.UserId=b.Id and a.Id=@id").AddInParameter("@id", 2))
{
result = await db.SelectOneAsync<Post>(command, (reader, idb) =>
{
return new Post
{
Title = ((string)reader["Title"]).Trim(),
Content = ((string)reader["Content"]).Trim(),
UserId = (int)reader["UserId"],
// populate relation object
User = new User
{
UserName = ((string)reader["UserName"]).Trim()
}
};
});
}
Relations, 2 possibilities:
- Create one sql query with aliases on table and columns and populate relation objects with data reader
- ... Or use EasyDb to get each relation (multiple queries/ server requests)
Examples:
1-1 relation
var db = new EasyDb();
// connection + mapping
// 1 post => 1 user (author)
var post = await db.SelectOneAsync<Post>(Check.Op("Id", 1));
post.User = await db.SelectOneAsync<User>(Check.Op("Id", post.UserId));
Note: for 0-1 relation, use a nullable with the "foreign key property" (example "UserId")
0-n relation
var db = new EasyDb();
// connection + mapping
// 1 user => 0-n posts
var user = await db.SelectOneAsync<User>(Check.Op("Id", 1));
user.Posts = await db.SelectAllAsync<Post>(null, Check.Op("UserId", user.Id));
var db = new EasyDb();
db.SetConnectionStringSettings(Constants.ConnectionString, Constants.ProviderName);
db.DefaultMappingBehavior = DefaultMappingBehavior.CreateEmptyTable;
var user = new User
{
UserName = "Marie"
};
var newId = await db.InsertAsync<User>(user);
With command factory
public class UserInsertFactory : IInsertCommandFactory<User>
{
public DbCommand CreateCommand(EasyDb db, User model)
{
return db.CreateSqlCommand("insert into [User](UserName) output inserted.id values(@username)")
.AddInParameter("@username", model.UserName);
}
public void SetNewId(DbCommand command, User model, object result)
{
model.Id = (int)result;
}
}
var db = new EasyDb();
db.SetConnectionStringSettings(Constants.ConnectionString, Constants.ProviderName);
var user = new User
{
UserName = "Marie"
};
var result = await db.InsertAsync<User>(new UserInsertFactory(), user);
var db = new EasyDb();
db.SetConnectionStringSettings(Constants.ConnectionString, Constants.ProviderName);
var user = new User
{
Id = 2,
UserName = "UserName updated"
};
var rowsAffected = await db.UpdateAsync<User>(user, Check.Op("Id", user.Id));
var db = new EasyDb();
db.SetConnectionStringSettings(Constants.ConnectionString, Constants.ProviderName);
var rowsAffected = await db.DeleteAsync<User>(Check.Op("Id", 3));
Allows to create quickly transaction and not have to define "BeginTransaction" or "transaction scope", open connection, etc.
Example
public class MyTransactionOperations : TransactionFactory
{
public override async Task ExecuteAsync(EasyDb db)
{
try
{
await db.InsertAsync<User>(new User { UserName = "New user 1" });
await db.InsertAsync<User>(new User { UserName = "New user 2" });
await db.InsertAsync<User>(new User { UserName = "New user 3" });
}
catch (System.Exception ex)
{
// throw exception to rollback
throw ex;
}
}
}
Execution
var db = new EasyDb();
// connection + mapping ...
var succcess = await db.ExecuteTransactionFactoryAsync(new MyTransactionOperations()); // true or false
Allows to register actions, and execute all actions on demand
Example:
var db = new EasyDb();
// connection + mapping ...
// 3 operations
db.AddPendingOperation(() => db.InsertAsync<User>(new User { UserName = "New user 1" }));
db.AddPendingOperation(() => db.InsertAsync<User>(new User { UserName = "New user 2" }));
db.AddPendingOperation(() => db.InsertAsync<User>(new User { UserName = "New user 3" }));
// execution
var success = await db.ExecutePendingOperationsAsync(); // if success, operations are clear
Example:
var db = new EasyDb();
db.SetConnectionStringSettings(Constants.ConnectionString, Constants.ProviderName);
using (var command = db
.CreateStoredProcedureCommand<User>("GetUser")
.AddInParameter("@id", 1))
{
var user = await db.SelectOneAsync<User>(command);
}
For example with MySQL:
DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `get_output_age` (IN `p_id` INT, OUT `p_age` INT) NO SQL
select age into p_age from users where id=p_id$$
DELIMITER ;
var db = this.GetDb();
// connection + mapping ...
using (var command = db.CreateStoredProcedureCommand<User>("get_output_age")
.AddInParameter("p_id", 2)
.AddOutParameter("p_age"))
{
await db.SelectOneAsync<User>(command);
var result = command.Parameters["p_age"];
}
For example with MySQL:
DELIMITER $$
CREATE DEFINER=`root`@`localhost` FUNCTION `get_username_function` (`p_id` INT) RETURNS VARCHAR(255) CHARSET latin1 NO SQL
begin
DECLARE result varchar(255);
select username into result from users where id=p_id;
return result;
end$$
DELIMITER ;
using (var command = db.CreateSqlCommand("SELECT `get_username_function`(@p0) AS `get_username_function`;")
.AddInParameter("@p0", 2)
.AddParameter("get_username_function", null, ParameterDirection.ReturnValue))
{
// Return value
var result = await db.ExecuteScalarAsync(command);
}