mardi 30 août 2016

ADO.Net Repository Pattern implementation from jgauffin not working

I am trying to implement the Repository Pattern explained by jgauffin at http://ift.tt/1ouayRg and getting crazy!

I have several problems to get it work. I have implemented a small SQL Server table called Employee:

enter image description here

I created a class for this employee:

Employee

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
}

IConnectionFactory

public interface IConnectionFactory
{
    IDbConnection Create();
}

Is it corect, that there is no correponding implemnetation for the IConnectionFactory interface? I couldnt find it!

AdoNetContext

public class AdoNetContext
{
    private readonly IDbConnection _connection;
    private readonly IConnectionFactory _connectionFactory;
    private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
    private readonly LinkedList<AdoNetUnitOfWork> _uows = new LinkedList<AdoNetUnitOfWork>();

    public AdoNetContext(IConnectionFactory connectionFactory)
    {
        _connectionFactory = connectionFactory;
        _connection = _connectionFactory.Create();
    }

    public IUnitOfWork CreateUnitOfWork()
    {
        var transaction = _connection.BeginTransaction();
        var uow = new AdoNetUnitOfWork(transaction, RemoveTransaction, RemoveTransaction);
        _rwLock.EnterWriteLock();
        _uows.AddLast(uow);
        _rwLock.ExitWriteLock();
        return uow;
    }

    public IDbCommand CreateCommand()
    {
        var cmd = _connection.CreateCommand();
        _rwLock.EnterReadLock();
        if (_uows.Count > 0)
            cmd.Transaction = _uows.First.Value.Transaction;
        _rwLock.ExitReadLock();
        return cmd;
    }

    private void RemoveTransaction(AdoNetUnitOfWork obj)
    {
        _rwLock.EnterWriteLock();
        _uows.Remove(obj);
        _rwLock.ExitWriteLock();
    }

    public void Dispose()
    {
        _connection.Dispose();
    }
}

AdoNetUnitOfWork

public class AdoNetUnitOfWork : IUnitOfWork
{
    private IDbTransaction _transaction;
    private readonly Action<AdoNetUnitOfWork> _rolledBack;
    private readonly Action<AdoNetUnitOfWork> _committed;

    public AdoNetUnitOfWork(IDbTransaction transaction, Action<AdoNetUnitOfWork> rolledBack, Action<AdoNetUnitOfWork> committed)
    {
        Transaction = transaction;
        _transaction = transaction;
        _rolledBack = rolledBack;
        _committed = committed;
    }

    public IDbTransaction Transaction { get; private set; }

    public void Dispose()
    {
        if (_transaction == null)
            return;
        _transaction.Rollback();
        _transaction.Dispose();
        _rolledBack(this);
        _transaction = null;
    }

    public void SaveChanges()
    {
        if (_transaction == null)
            throw new InvalidOperationException("May not call save changes twice.");
        _transaction.Commit();
        _committed(this);
        _transaction = null;
    }
}

AppConfigConnectionFactory

public class AppConfigConnectionFactory
{
    private readonly DbProviderFactory _provider;
    private readonly string _connectionString;
    private readonly string _name;

    public AppConfigConnectionFactory(string connectionName)
    {
        if (connectionName == null) throw new ArgumentNullException("connectionName");
        var conStr = ConfigurationManager.ConnectionStrings[connectionName];
        if (conStr == null)
            throw new ConfigurationErrorsException(string.Format("Failed to find connection string named '{0}' in app/web.config.", connectionName));
        _name = conStr.ProviderName;
        _provider = DbProviderFactories.GetFactory(conStr.ProviderName);
        _connectionString = conStr.ConnectionString;
    }

    public IDbConnection Create()
    {
        var connection = _provider.CreateConnection();
        if (connection == null)
            throw new ConfigurationErrorsException(string.Format("Failed to create a connection using the connection string named '{0}' in app/web.config.", _name));
        connection.ConnectionString = _connectionString;
        connection.Open();
        return connection;
    }
}

Repository

public abstract class Repository<TEntity> where TEntity : new()
{
    AdoNetContext _context;

    public Repository(AdoNetContext context)
    {
        _context = context;
    }

    protected AdoNetContext Context { get; }

    protected IEnumerable<TEntity> ToList(IDbCommand command)
    {
        using (var reader = command.ExecuteReader())
        {
            List<TEntity> items = new List<TEntity>();
            while (reader.Read())
            {
                var item = new T();
                Map(reader, item);
                items.Add(item);
            }
            return items;
        }
    }

    protected abstract void Map(IDataRecord record, TEntity entity);
}

EmployeeRepository

public class EmployeeRepository : Repository<Employee>
{
    public EmployeeRepository(AdoNetContext context) : base(context)
    {
    }

    public void Create(Employee employee)
    {
        using (var command = _connection.CreateCommand())
        {
            command.CommandText = @"INSERT INTO Employees (Name) VALUES(@name)";
            command.AddParameter("name", employee.Name);
            command.ExecuteNonQuery();
        }

        //todo: Get identity. Depends on the db engine.
    }
    public void Update(Employee employee)
    {
        using (var command = _connection.CreateCommand())
        {
            command.CommandText = @"UPDATE Employees SET Name = @name WHERE Id = @id";
            command.AddParameter("name", employee.Name);
            command.AddParameter("id", employee.Id);
            command.ExecuteNonQuery();
        }
    }
    public void Delete(int id)
    {
        using (var command = _connection.CreateCommand())
        {
            command.CommandText = @"DELETE FROM Employees WHERE Id = @id";
            command.AddParameter("id", id);
            command.ExecuteNonQuery();
        }
    }

    public IEnumerable<Employee> FindUsers(string name)
    {
        using (var command = _connection.CreateCommand())
        {
            command.CommandText = @"SELECT * FROM Employees WHERE Name LIKE @name";
            command.AddParameter("firstName", name + "%");
            return ToList(command);
        }
    }

    //public IEnumerable<Employee> FindBlocked()
    //{
    //    using (var command = _connection.CreateCommand())
    //    {
    //        command.CommandText = @"SELECT * FROM Users WHERE Status = -1";
    //        return ToList(command);
    //    }
    //}

    protected override void Map(IDataRecord record, Employee employee)
    {
        employee.Name = (string)record["Name"];
        employee.Id = (int)record["Id"];
    }
}

And that should be the app

    static void Main(string[] args)
    {
        // during app start
        var factory = new AppConfigConnectionFactory("RepositoryPattern");
        // during start of the current session

        var context = new AdoNetContext();
        // for the transaction
        using (var uow = context.CreateUnitOfWork())
        {
            var repos1 = new EmployeeRepository(context);
            var repos2 = new EmployeeRepository(context);
            // do changes
            // [...]
            uow.SaveChanges();
        }
    }

But i am not getting it work! I get errors in two files:

enter image description here

It tells me that the AdoNetContext has no parameter of type connectionFactory. I dont know what to add here.

And in the EmployeeRepository file i get errors for

using (var command = _connection.CreateCommand())

enter image description here

What is here wrong? Maybe someone can explaing me what i am doing wrong!? This is driving me crazy!

Aucun commentaire:

Enregistrer un commentaire