Пользовательская обертка ORM C # Dapper

c# dapper design-patterns

Вопрос

Я разрабатываю услуги asp.net web API REST. Мои данные хранятся в реляционной базе данных MySQL. На уровне доступа к данным я хотел бы использовать DARM Micro ORM, поэтому я хотел бы создать какие-то свои собственные методы обертки ORM. Если в будущем я решит перейти на другую ORM, мне не нужно будет переписывать весь код слоя DAL.

Что вы думаете о моем подходе? Вот код:

public abstract class BaseORMCommandSettings //SQL command base class
{
    public string CommandText { get; private set; }
    public object Parameters { get; private set; }
    public IDbTransaction Transaction { get; private set; }
    public int? CommandTimeout { get; private set; }
    public CommandType? CommandType { get; private set; }
    public CancellationToken CancellationToken { get; private set; }

    public BaseORMCommandSettings(string commandText, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null,
                             CommandType? commandType = null, CancellationToken cancellationToken = default(CancellationToken))
    {
        this.CommandText = commandText;
        this.Parameters = parameters;
        this.Transaction = transaction;
        this.CommandTimeout = commandTimeout;
        this.CommandType = commandType;
        this.CancellationToken = cancellationToken;
    }
}

public class DapperCommandSettings : BaseORMCommandSettings//dapper cmd impl
{
    public CommandFlags Flags { get; private set; }

    public DapperCommandSettings(string commandText, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null,
                             CommandType? commandType = null, CancellationToken cancellationToken = default(CancellationToken), CommandFlags flags = CommandFlags.Buffered)
         :base(commandText, parameters, transaction, commandTimeout, commandType, cancellationToken)
    {
        this.Flags = flags;
    }
}

public interface ICustomORM //base interface, for now have only generic Read 
                            list method
{
    IEnumerable<T> Read<T>(BaseORMCommandSettings cmd);
}

public class DapperORM : ICustomORM //my own dapper ORM wrapper implentation
{
    private readonly IDbConnection con;

    public DapperORM(IDbConnection con)
    {
        this.con = con;
    }

    public IEnumerable<T> Read<T>(BaseORMCommandSettings cmd)
    {
        var cmdDapper = cmd as DapperCommandSettings;
        var dapperCmd = new CommandDefinition(cmdDapper.CommandText, cmdDapper.Parameters, cmdDapper.Transaction,
                                              cmdDapper.CommandTimeout, cmdDapper.CommandType, cmdDapper.Flags, 
                                              cmdDapper.CancellationToken);

        return con.Query<T>(dapperCmd);
    }
}

Заранее спасибо за любую помощь.

Принятый ответ

Ага. Пожалуйста, не делайте этого. Dapper существует и пользуется успехом, который он делает, потому что он обеспечивает краткий, выразительный способ делать ADO. Это не ORM. Если вы завернете dapper, вы потеряете краткий выразительный интерфейс, и вы потеряете смысл. ORM (который не используется) частично существует для обеспечения переносимости DB. Начав говорить о переносимости ORM, люди перестанут ударять головой о стену, в отчаянии! Просто используйте Dapper и полюбуйтесь им.


Популярные ответы

Я предлагаю вам перейти к описанию OO и создать объект, который имеет только один метод, который возвращает последовательность некоторого типа объекта. Таким образом вы можете создать объект PAge и передать параметры через конструктор, чтобы вы могли создавать различные типы страниц: SqlPages, DapperPages, TestablePages и т. Д. Таким образом, у вас есть гибкий способ работы, и вы можете создавать свой код и оставлять детали инфраструктуры / базы данных, реализованные в конце. Я бы инкапсулировал детали dtabases внутри объекта, не позволяя деталям распространяться через ваш код:

/// <summary>
/// DTO
/// </summary>
public class MyDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Value { get; set; }
}

/// <summary>
/// Define a contract that get a sequence of something
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IFetch<T>
{
    IEnumerable<T> Fetch();
}

/// <summary>
/// Define a pageTemplate
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class PageTemplate<T> : IFetch<T>
{
    protected readonly int pageSize;
    protected readonly int page;

    public PageTemplate(int page, int pageSize)
    {
        this.page = page;
        this.pageSize = pageSize;
    }
    public abstract IEnumerable<T> Fetch();
}

/// <summary>
/// Design a MyDto Page object, Here you are using the Template method
/// </summary>
public abstract class MyDtoPageTemplate : PageTemplate<MyDto>
{
    public MyDtoPageTemplate(int page, int pageSize) : base(page, pageSize) { }
}

/// <summary>
/// You can use ado.net for full performance or create a derivated class of MyDtoPageTemplate to use Dapper
/// </summary>
public sealed class SqlPage : MyDtoPageTemplate
{
    private readonly string _connectionString;
    public SqlPage(int page, int pageSize, string connectionString) : base(page, pageSize)
    {
        _connectionString = connectionString;
    }

    public override IEnumerable<MyDto> Fetch()
    {
        using (var connection = new SqlConnection(_connectionString))
        {
            //This can be injected from contructor or encapsulated here, use a Stored procedure, is fine
            string commandText = "Select Something";
            using (var command = new SqlCommand(commandText, connection))
            {
                connection.Open();
                using (var reader = command.ExecuteReader())
                {
                    if (reader.HasRows) yield break;
                    while (reader.Read())
                    {
                        yield return new MyDto()
                        {
                            Id = reader.GetInt32(0),
                            Name = reader.GetString(1),
                            Value = reader.GetString(2)
                        };
                    }
                }
            }
        }
    }
}

/// <summary>
/// You can test and mock the fetcher
/// </summary>
public sealed class TestPage : IFetch<MyDto>
{
    public IEnumerable<MyDto> Fetch()
    {
        yield return new MyDto() { Id = 0, Name = string.Empty, Value = string.Empty };
        yield return new MyDto() { Id = 1, Name = string.Empty, Value = string.Empty };
    }
}

public class AppCode
{
    private readonly IFetch<MyDto> fetcher;
    /// <summary>
    /// From IoC, inject a fetcher object
    /// </summary>
    /// <param name="fetcher"></param>
    public AppCode(IFetch<MyDto> fetcher)
    {
        this.fetcher = fetcher;
    }
    public IEnumerable<MyDto> FetchDtos()
    {
        return fetcher.Fetch();
    }
}

public class CustomController
{
    private readonly string connectionString;

    public void RunSql()
    {
        var fetcher = new SqlPage(1, 10, connectionString);
        var appCode = new AppCode(fetcher);
        var dtos = appCode.FetchDtos();
    }

    public void RunTest()
    {
        var fetcher = new TestPage();
        var appCode = new AppCode(fetcher);
        var dtos = appCode.FetchDtos();
    }
}


Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему