При попытке вставить сущность в базу данных, используя unitOfWork с TransactionsScope.На самом деле я получу ожидаемые результаты от пользователя, которого я добавил (int ожидается, Userid = uowFactory.Create (). AddBasicUser (user);).Но после удаления UnitOfWork и TransactionsScope я не вижу никаких изменений в базе данных.Это заставляет меня поверить в то, что я неправильно реализовал транзакцию TransactionsScope в UnitOfWork.
Я также заметил, что при запуске (отладке) следующего unitTest и с точкой останова в следующей строке: 60, я не могу запроситьтаблица базы данных «BasicUser» через mssql mngmnt studio (заблокировано, JustSaying: выполнение запроса ...).
Сказанный UnitTest (ссылка на изображение)
Сам UnitTest проходит.
Вопрос: Почему кажется, что UnitOfWork работаеткак и предполагалось, но я не вижу каких-либо изменений в базе данных?И как получается, что Db блокируется, когда транзакцияcope / UnitOfWork уже удалена.
Большое спасибо!
Код ссылки:
IUnitOfWorkFactory
namespace DomainServices
{
public interface IUnitOfWorkFactory
{
IUnitOfWork Create();
}
}
UnitOfWorkFactory
using System;
using DomainServices;
using System.Transactions;
namespace DataAccess
{
public class UnitOfWorkFactory
{
private readonly IsolationLevel _isolationLevel;
private readonly Func<IsolationLevel, IUnitOfWork> CreateUnitOfWork;
public UnitOfWorkFactory(Func<IsolationLevel, IUnitOfWork> createUnitOfWork, IsolationLevel isolationLevel)
{
_isolationLevel = isolationLevel;
CreateUnitOfWork = createUnitOfWork;
}
public IUnitOfWork Create()
{
return CreateUnitOfWork.Invoke(_isolationLevel);
}
}
}
IUnitOfWork
using System;
namespace DomainServices
{
public interface IUnitOfWork : IDisposable
{
IUserRepository UserRepository { get; }
void Dispose();
void Commit();
}
}
UnitOfWork
using DataAccess.Repository;
using DomainServices;
using System.Transactions;
namespace DataAccess
{
public class UnitOfWork : IUnitOfWork
{
private readonly DatabaseConnection _dbConnection;
private readonly TransactionScope _transactionScope;
private bool isDisposed;
public IUserRepository _userRepository;
public IUserRepository UserRepository
{
get
{
if (this._userRepository == null)
{
this._userRepository = new UserRepository(this._dbConnection, this._transactionScope);
}
return this._userRepository;
}
}
public UnitOfWork(DatabaseConnection dbConnection, IsolationLevel isolationLevel)
{
this.isDisposed = false;
this._dbConnection = dbConnection;
this._transactionScope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions
{
IsolationLevel = isolationLevel,
Timeout = TransactionManager.DefaultTimeout
});
}
public void Commit()
{
this._transactionScope.Complete();
}
public void Dispose()
{
this.Dispose(true);
}
protected void Dispose(bool disposing)
{
if (!this.isDisposed)
{
if (disposing)
{
this._transactionScope.Dispose();
}
this.isDisposed = true;
}
}
}
}
IUserRepository
using Domain;
using System.Collections.Generic;
namespace DomainServices
{
public interface IUserRepository
{
int AddBasicUser(BasicUser basicUser);
IEnumerable<BasicUser> GetAllBasicUsers();
}
}
UserRepository
using System.Collections.Generic;
using Domain;
using DomainServices;
using System.Data.SqlClient;
using System;
using System.Transactions;
namespace DataAccess.Repository
{
public class UserRepository : IUserRepository
{
private readonly DatabaseConnection _dbConnection;
private readonly TransactionScope _transaction;
public UserRepository(DatabaseConnection dbConnection, TransactionScope transaction)
{
this._dbConnection = dbConnection;
this._transaction = transaction;
}
public int AddBasicUser(BasicUser basicUser)
{
string QueryString = "INSERT INTO BasicUser (Username, RegisterDate) OUTPUT Inserted.Id VALUES (@username, @registerDate);";
TODO MarWolt: Use a Maybe instead of magic values.
int basicUserId = -1;
//using (TransactionScope scope = new TransactionScope())
using (SqlConnection conn = new SqlConnection(_dbConnection.ConnectionString))
using (SqlCommand cmd = new SqlCommand(QueryString, conn))
{
conn.Open();
cmd.Parameters.AddWithValue("Username", basicUser.UserName.Value);
cmd.Parameters.AddWithValue("RegisterDate", basicUser.RegisterDate);
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
basicUserId = Convert.ToInt32(reader["Id"]);
}
}
scope.Complete();
}
return basicUserId;
}
public IEnumerable<BasicUser> GetAllBasicUsers()
{
var QueryString = "SELECT Id, Username, LastLogin, RegisterDate FROM BasicUser;";
var result = new List<BasicUser>();
using (var conn = new SqlConnection(_dbConnection.ConnectionString))
using (var cmd = new SqlCommand(QueryString, conn))
{
conn.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
result.Add(CreateBasicUserFromReader(reader));
}
return result;
}
}
private BasicUser CreateBasicUserFromReader(SqlDataReader reader)
{
return new BasicUser(
id: Convert.ToInt32(reader["Id"]),
userName: new UserName(Convert.ToString(reader["Username"])),
lastLogin: DateTime.Now, //Convert.ToDateTime(reader["LastLogin"]), //TODO MarWolt This...
registerDate: Convert.ToDateTime(reader["RegisterDate"]),
rideTokens: new List<RideToken>()
);
}
}
}
UnitTestProject
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Transactions;
using DataAccess;
using DataAccess.Repository;
using Domain;
using DomainServices;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTestProject
{
[TestClass]
public class UserRepositoryTests
{
private UnitOfWorkFactory uowFactory;
private DatabaseConnection testDatabaseConnection;
public UserRepositoryTests()
{
testDatabaseConnection = new DatabaseConnection(
"Server=.\\SQLEXPRESS;Initial Catalog=TestDb;User Id=DbUser;Password=DbUserPassword;Integrated Security=false;Connect Timeout=5;");
uowFactory = new UnitOfWorkFactory((IsolationLevel) => new UnitOfWork(testDatabaseConnection, IsolationLevel), IsolationLevel.ReadCommitted);
}
[TestInitialize()]
public void Initialize()
{
//TODO MarWolt: delete everything from the database on a clean way.
using (SqlConnection conn = new SqlConnection(testDatabaseConnection.ConnectionString))
using (SqlCommand cmd = new SqlCommand(Properties.Resources.ClearDbSqlScript, conn))
{
conn.Open();
cmd.ExecuteNonQuery();
}
}
[TestMethod]
public void AddNewBasicUser()
{
var user = new BasicUser(new UserName("UnitTestBasicUserName"), DateTime.UtcNow, new List<RideToken>() { });
var users = uowFactory.Create().UserRepository.GetAllBasicUsers();
Assert.AreEqual(0, users.Count());
using (IUnitOfWork unitOfWork = uowFactory.Create())
{
unitOfWork.UserRepository.AddBasicUser(user);
unitOfWork.Commit();
}
users = uowFactory.Create().UserRepository.GetAllBasicUsers();
Assert.AreEqual(1, users.Count());
var recievedUser = users.First();
Assert.AreEqual(user.UserName.Value, recievedUser.UserName.Value);
// I'm unable to query the database via mssql server management studio when this breakpoint is active.
// I would actually expect it already to be done after line 51.
Console.WriteLine(string.Empty);
}
}
}