Как упростить мой доступ к данным или переложить его в ОРМ


В здании любого нового приложения я в конечном итоге, используя что-то похожее на этот код тип доступа к данным. Я это хорошо знаю, и он работает хорошо. Но желание попробовать что-то новое на новый проект, я думал, что смогу пересматривать его снова и, возможно, упростить его более или переместить его в ОРМ. Я смотрел на щегольски, хотя я знаю, что есть целый ряд ОРМ по.

Это код, чтобы получить список каких-либо данных. Что-то часто завершена в мой код.
"Бизнес" код

public class MyClassA
{
    public int Id { get; set; }
    public DateTime CreatedDate { get; set; }
    // Many other properties

    internal static MyClassA BuildPostsFromRow(DataRow dr)
    {
        MyClassA _myclass = new MyClassA();

        _myclass.Id = (int)dr["ContentId"];
        /*   Many other properties   */
        _myclass.CreatedDate = (DateTime)dr["CreatedDate"];

        return _myclass;
    }

    public List<Post> ListRecentForInstance(int id)
    {
        DataAccess _da = new DataAccess();
        return _da.ListForInstance(id);
    }
}

Мой фактический доступ к данным

public class DataAccess
{
    public readonly string Con = ConfigurationManager.ConnectionStrings["MyDb"].ToString();

    public List<MyClassA> ListForInstance(int instanceId)
    {
        var _sql = @"
            SELECT Id, 
                   CreatedDate,
                   ...other data
              FROM MyData
            WHERE InstanceId = @instanceId
            ";
        SqlParameter[] _params = new SqlParameter[1];
        _params[0] = new SqlParameter("@instanceId", SqlDbType.Int) { Value = instanceId };

        return DataHelper.ExecuteQuery(Con, _sql, _params).Tables[0].AsEnumerable()
            //MyClassA.BuildPostsFromRow can also be split out to be inline rather and 
            // calling another method but I'm reusing the BuildPostsFromRow method for now
                           .Select(row => MyClassA.BuildPostsFromRow(row))
                           .ToList();
    }
}

public class DataHelper
{
    // A few other similar methods to wrap up data access code and sql logging
    // only the DataAccess class calls these methods
    public static DataSet ExecuteQuery(string connection, string sql, params SqlParameter[] paramsToCommand)
    {
        using (DataSet ds = new DataSet())
        {
            using (SqlConnection _con = new SqlConnection(connection))
            {
                if (_con.State == ConnectionState.Closed)
                    _con.Open();

                using (SqlCommand _cmd = new SqlCommand(sql, _con))
                {
                    AttachParameters(_cmd, paramsToCommand);

                    using (SqlDataAdapter adapter = new SqlDataAdapter(_cmd))
                    {
                        adapter.Fill(ds);
                    }
                }
            }
            return ds;
        }
    }

    private static void AttachParameters(SqlCommand command, SqlParameter[] commandParameters)
    {
        if (command == null)
            throw new ArgumentNullException("command");

        if (commandParameters != null)
        {
            foreach (SqlParameter p in commandParameters)
            {
                if (p != null)
                {
                    if ((p.Direction == ParameterDirection.InputOutput || p.Direction == ParameterDirection.Input) && (p.Value == null))
                        p.Value = DBNull.Value;

                    command.Parameters.Add(p);
                }
            }
        }
    }
}

Да я уверен, что каждый думает "о великих другую даль". Но я действительно хочу некоторые изменения. Я бы очень хотел несколько советов о том, как отойти от этой модели и проскользнуть в что-то более современное.

Редактировать:
На мысль о тестировании, я провел сегодня, разбираясь в LINQ 2 SQL и щеголеватый. Я очень хочу работать, я действительно. Так вот мое приложение, как коротким и сладким, и нет ничего, как это:

class Program
    {
        public static readonly string connectionString = 
@"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\App_Data\Database1.mdf;Integrated Security=True;User Instance=True";
    public static SqlConnection GetOpenConnection()
    {
        var connection = new SqlConnection(connectionString);
        if (connection.State != ConnectionState.Open)
            connection.Open();
        return connection;
    }
    SqlConnection connection = GetOpenConnection();

    static void Main(string[] args)
    {
// Added as it was taking time the first time to connect the db to the instance
            using (var connection = new SqlConnection(connectionString))
            {
                if (connection.State != ConnectionState.Open)
                    connection.Open();
            }

        Stopwatch sw1 = new Stopwatch();
        sw1.Start();
        int i = 0;

        // Linq2Sql
        for (i = 0; i <= 100; i++)
        {
            CoreClassesDataContext _dc = new CoreClassesDataContext();

            var _posts = (from p in _dc.Posts

                          select p).ToList();

            foreach (var item in _posts)
            {
                int id = item.Id;
            }
            _dc.Dispose();
        }
        sw1.Stop();
        Console.WriteLine("Linq 2 Sql");
        Console.WriteLine(sw1.ElapsedMilliseconds);
        sw1.Reset();
        sw1.Start();
        // Dapper
        for (i = 0; i <= 100; i++)
        {
            Program _p = new Program();
            var data = _p.connection.Query<Post>("select Id, PostContent from Post").ToList();
            foreach (var item in data)
            {
                int id = item.Id;
            }
        }
        sw1.Stop();
        Console.WriteLine("Dapper");
        Console.WriteLine(sw1.ElapsedMilliseconds);
        sw1.Restart();

        // Plain ol ADO
        for (i = 0; i <= 100; i++)
        {
            Data _d = new Data();
            foreach (var item in _d.BuildList())
            {
                int id = item.Id;
            }
        }
        sw1.Stop();
        Console.WriteLine("DAL");
        Console.WriteLine(sw1.ElapsedMilliseconds);

        Console.ReadKey();
    }
    class Data
    {
        public List<Post> BuildList()
        {
            var _sql = "select Id, PostContent from Post";
            return DataHelper.ExecuteQuery(connectionString, _sql).Tables[0].AsEnumerable()
                           .Select(row => new Post { Id = (int)row["Id"],
                                                     PostContent = (string)row["PostContent"]
                           }).ToList();
        }
    }

    class Post
    {
        public int Id { get; set; }
        public string PostContent { get; set; }
    }
}

После многих, много работает, он почти всегда работает такой или близко к:

Linq 2 Sql
   205
Dapper
   394
DAL
   105

Я думал, что ОРМ было помочь со скоростью? Так почему же мои мертвы простой, ручной даль лупят штаны как? Я делаю что-то неправильно?



2487
4
задан 1 ноября 2011 в 08:11 Источник Поделиться
Комментарии
3 ответа

Ваш заголовок вопрос состоит из двух частей.

С первой частью, "как упростить", я бы сказал, что вы не должны хлопотать. Все эти усилия уже в другие рамки, будь они маленькие помошники как щеголь или полнофункциональный моделей ORM, как NHibernate на. Мир, как вы уже поняли, двинулся дальше.

Чтобы ответить на вторую часть, "сдвиг его в ОРМ", я бы предположил что это не возможно. На примере эф код первого или свободно NHibernate на (желательно с автоматический маппинг), вы начинаете свой покос, что модель вашего домена, в случае вашего кода выше, класс один 'пост'. Остальная часть кода уже в рамках.

Мои советы о том, как подобрать современную модель, как вы выразились, будет делать упражнения. Отложить в коде у вас на некоторое время и посмотреть на создание небольшого приложения для себя, что использует эф код первого или свободно NHibernate с автоматический маппинг. Вы даже могли видеть, как легко это филиал/рефакторинг и использовать другие ОРМ - отличный способ выучить основы.

Обновление: надеюсь, это реализация необработанных PostRepository с помощью Fluent NHibernate на автоматический маппинг будет способствовать вам в ваших исследованиях. Есть отверстия в следующую, но вы могли бы заставить его работать. Использовать NuGet, чтобы принести свободно NHibernate на.

public static class Configuration
{
public static FluentConfiguration GetConfiguration(string connectionString)
{
var executingAssembly = Assembly.GetExecutingAssembly();

var configuration =
Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(connectionString))
.Mappings(
m =>
m.AutoMappings.Add(
AutoMap.Assemblies(new AutomappingConfiguration(), executingAssembly)
.IgnoreBase<Entity>())
.ExposeConfiguration(BuildSchema);

return configuration;
}

// Set SchemaScript to True to see the generated DDL.
// Set SchemaExport to True to build the database.
private static void BuildSchema(NHibernate.Cfg.Configuration configuration)
{
new SchemaExport(configuration)
.SetOutputFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "schema.sql"))
.Create(Properties.Settings.Default.SchemaScript, Properties.Settings.Default.SchemaExport);
}
}

Следующий класс позволяет указать пространство имен Вашего лица (т. е. модели 'Post').

public class AutomappingConfiguration : DefaultAutomappingConfiguration
{
public override bool ShouldMap(Type type)
{
return type.Namespace == "MyPostProject.Entities";
}
}

NHibernate на любит все иметь удостоверение личности. Вот базовый класс для этого. Все должно быть виртуальными, так что NHibernate может создать прокси для вашей модели объектов.

public abstract class Entity
{
public virtual int Id { get; protected internal set; }
}

Вот такой элементарной сущности.

public class Post : Entity
{
public virtual string Content { get; set; }
}

Базовый класс репозитория, который использует сессии в качестве единицы работы.

public abstract class Repository<TEntity> : IRepository<TEntity> where TEntity : Entity
{
protected readonly ISession Session;

protected Repository(ISessionSource sessionSource)
{
this.Session = sessionSource.CreateSession();
}

public virtual void SaveOrUpdate(TEntity entity)
{
this.Session.SaveOrUpdate(entity);
this.Session.Flush();
}

public virtual TEntity GetById(int id)
{
return this.Session.Get<TEntity>(id);
}

public virtual IEnumerable<TEntity> GetAll()
{
return this.Session.CreateCriteria<TEntity>().List<TEntity>();
}
}

В PostRepository.

public class PostRepository : Repository<Post>, IDeletionRepository<Post>, IPostRepository
{
public PostRepository(ISessionSource sessionSource) : base(sessionSource)
{
}

public void Delete(Post post)
{
this.Session.Delete(post);
this.Session.Flush();
}
}

Тест на стойкость, который проверяет ваши сопоставления являются правильными.

using Configuration = MyPostProject.Configuration;

[TestClass]
public class PersistenceSpecificationTests
{
private ISession session;

[TestInitialize]
public void SetUp()
{
var sessionSource = new SessionSource(Configuration.GetConfiguration("Data Source =.; Initial Catalog =Post; Integrated Security=True;"));
session = sessionSource.CreateSession();
}

[TestMethod]
public void CanMapPost()
{
using (var transaction = session.BeginTransaction())
{
new PersistenceSpecification<Post>(session)
.CheckProperty(m => m.Content, "Lorum ipsum")
.VerifyTheMappings();

transaction.Rollback();
}
}
}

Создать пустой пост (использовать объект генератора мать, как NBuilder или AutoFixture) и попробовать реализовать свой репозиторий.

    [TestMethod]
public void ShouldSaveUser()
{
using (var transaction = session.BeginTransaction())
{
session.Save(dummyPost);
transaction.Rollback();
}
}

Там очень много больше к тому же с помощью Fluent NHibernate на переопределяет, что позволить вам создавать малые изменения по умолчанию автоматический маппинг, если требуется, и конвенциях, которые довольно ваш код DDL. Репозиторий должен уметь принимать технические характеристики (критерии поиска).

3
ответ дан 2 ноября 2011 в 03:11 Источник Поделиться

Если NHibernate на слишком много перебор, вы обязательно должны использовать в LINQ-в-SQL-запрос. Идеально подходит для небольших сценария.

2
ответ дан 3 ноября 2011 в 05:11 Источник Поделиться

Я большой поклонник рамках организации. Я, как правило, используют базу данных и затем обновить модель данных из таблиц, которые я выделяю. Затем я использовать LINQ с лямбда выражением. С этой комбинации, я могу написать довольно компактный код и никаких SQL. Я рекомендую дать ему попробовать.

http://msdn.microsoft.com/en-us/data/gg685489

2
ответ дан 6 ноября 2011 в 01:11 Источник Поделиться