Сравнение entity framework и dapper
There are a few performance comparisons between Dapper (which seems to be the fastest, most popular "micro ORM tool"). Now it's September 2014 and we have Entity Framework 6 (not 5, or 4) and Dapper is still around.
We will begin developing a huge database n-tier application (database has 700 tables). And some of the queries that need to be run are quite time-sensitive.
- Does anyone have any updates on performance regarding EF 6.1.x? This concerns general queries made within a DbContext.
- I suppose I cannot use nicely formatted LINQ queries with Dapper. Do you have experience with that? Is it worth losing LINQ for the additional speed?
- IS Dapper still under active, constant development? GitHub tells me yes, but as with Subsonic, that can change rather quickly.
- Is it feasable/doable to mix Dapper and EF? Dapper when we need the speed, otherwise EF.
Testing Queries
This is one of my tests. In the arrange part I get the actual dbConnection and inject that in order to run the SQL against the database.
In the Act section, I always pass ALL possible query parameters to the query handler. This will ensure all where clause statements are tested.
If an error occurs with the SQL syntax the catch exception will display a friendly message to me in my test runner.
At the end you will find I assert that the properties in the query result are all accounted for by the SQL select!
This might not be the best function ever but it saved me in a few cases where I had forgot to add a SQL result for one of the properties I was expecting to return.
Looking to expand your technical team?👨👱 We at Code&Devs provide skilled dedicated developers. Let’s grow together.🏆
Commands
I’ll give a small example of how we use commands in our system. Leveraging AutoMapper and Entity Framework for commands was a good fit for us. Right now we have a custom implementation to call our commands due to how we wanted to do validation.
You can see that this command implements an ICommandHandler. This is a custom interface we use to implement business validation. I would like to find a way to use MediatR to do the validation we are doing though. Here we should be injecting an AutoMapper dependency. But this is how it is for now :)
Our commands are using the decorator pattern to handle transactions and validation. You might have wondered where _context.SaveChanges() was :). For now I’m going to skip this because this post is getting a little long! There are a lot of things we have done to streamline validation of commands that would be a whole post on its own.
Why Dapper?
Инфраструктура в Entity Framework Core с точки зрения DDD
С точки зрения DDD важной особенностью EF является возможность использования сущностей предметной области POCO, которые в терминологии EF также называются сущностями code-first. При использовании сущностей предметной области POCO ваши классы модели предметной области являются неустойчивыми, следуя принципам Persistence Ignorance (независимости сохраняемости) и Infrastructure Ignorance (независимости инфраструктуры).
В шаблонах DDD вы должны инкапсулировать правила и поведение домена в самом классе сущностей, чтобы он мог управлять инвариантами, проверками и правилами при доступе к любой коллекции. Таким образом, в DDD не рекомендуется разрешать общий доступ к коллекциям дочерних сущностей или объектов значений. Вместо этого следует предоставить методы, определяющие, как и когда могут обновляться поля и коллекции свойств, и какое поведение и действия должны осуществляться, когда это происходит.
Начиная с EF Core 1.1, для удовлетворения этих требований DDD можно создавать в своих сущностях простые поля вместо общедоступных свойств. Если вы не хотите, чтобы поле сущности было доступно извне, можно просто создать атрибут или поле вместо свойства. Можно также использовать методы задания закрытых свойств.
Таким же образом теперь можно иметь доступ только для чтения к коллекциям с помощью открытого свойства, типизированного как IReadOnlyCollection , который поддерживается членом частного поля для коллекции (например, a List ) в сущности, которая использует EF для сохраняемости. В предыдущих версиях Entity Framework требовалось наличие свойств коллекции для поддержки ICollection , что означало, что любой разработчик, использующий родительский класс сущностей, может добавлять или удалять элементы с помощью его коллекций свойств. Эта возможность противоречила бы рекомендуемым шаблонам в DDD.
Вы можете использовать закрытую коллекцию при предоставлении объекта IReadOnlyCollection только для чтения, как показано в следующем примере кода.
Свойство OrderItems может быть доступно только для чтения с помощью IReadOnlyCollection . Этот тип доступен только для чтения, поэтому он защищен от обычных внешних обновлений.
При использовании полей вместо свойств сущность OrderItem сохраняется так же, как если бы она имела свойство List . Однако она предоставляет единственный метод доступа AddOrderItem для добавления в заказ новых элементов. В результате поведение и данные оказываются связаны друг с другом и будут согласованными во всем коде приложения, использующем модель предметной области.
Реализация шаблона спецификации запроса
Как говорилось ранее в разделе, посвященном проектированию, шаблон спецификации запроса — это шаблон предметно-ориентированного проектирования, в котором можно поместить определение запроса с дополнительной логикой сортировки и разбиения на страницы.
Шаблон спецификации запроса определяет запрос в объекте. Например, чтобы инкапсулировать постраничный запрос, который выполняет поиск некоторых продуктов, вы можете создать спецификацию PagedProduct, которая принимает необходимые входные параметры (номер страницы, размер страницы, фильтр и т. д.). Затем в любом методе репозитория (обычно в перегрузке List()) вы можете принять IQuerySpecification и запустить ожидаемый запрос на основе этой спецификации.
Примером универсального интерфейса спецификации является следующий код, который похож на код, используемый в эталонном приложении eShopOnWeb.
Реализация базового класса универсальной спецификации выглядит следующим образом.
Следующая спецификация загружает одну сущность корзины, заданную идентификатором корзины или идентификатором покупателя, которому принадлежит корзина. Она будет безотлагательно загружать коллекцию Items корзины.
И, наконец, ниже вы видите, как универсальный репозиторий EF может использовать такую спецификацию для фильтрации и безотложной загрузки данных, связанных с типом T заданной сущности.
Помимо инкапсуляции логики фильтрации, эта спецификация может указывать форму возвращаемых данных, включая свойства, которые следует заполнить.
Хотя не рекомендуется возвращать IQueryable из репозитория, совершенно нормально использовать их в репозитории для создания набора результатов. Вы видели применение этого подхода в методе List выше, где промежуточные выражения IQueryable использовались для построения списка Includes запроса перед выполнением запроса с условиями спецификации в последней строке.
Okay, i know that you have seen other benchmarks on the internet showing dapper is faster than Entity Framework. I found it unfair to compare an auto-generated SQL to the one written by a good developer, so decided to benchmark it for below use cases. Including linq vs Plain Queries comparisons and also the affect of AsNoTracking().
Use Cases:
- Select 5000 rows out of 500k rows.
- Insert new row.
- Update a row column at index 5001.
Nugets:
Dapper’s query looks like this.
Notice that i used AsNoTracking() for performance hit. As it will indicate EF not to track the models for change.
Notice that Entity Framework Core 2’s plain sql commands are almost giving the same result as Dapper(very little difference). Also notice that AsNoTracking(), when applied gives faster response.
Caution:
Always run your code in release mode for performance benchmarks. Running a code in Debug mode can be 10x slower. So, publish it, got to the published directory and run the below command in cmd.
Dapper is faster than the Entity Frame Core 2. If performance is your biggest concern, Use dapper! However, if you want speedy development and can compromise a little bit on performance, use entity framework instead.
So, don’t select either based on my benchmark. You can download the source code and it is highly recommended to test it yourself for different scenarios before making a decision.
I’m missing something? or your tests gave different results? let me know by sharing your valuable feedback.
Использование теневых свойств в EF Core, скрытых на уровне инфраструктуры
Теневые свойства в EF Core — это свойства, которые не существуют в вашей модели классов сущностей. Значения и состояния этих свойств сохраняются только в классе ChangeTracker на уровне инфраструктуры.
Текучий API и метод OnModelCreating
Как уже упоминалось, для изменения соглашений и сопоставлений можно использовать метод OnModelCreating класса DbContext.
Микрослужба заказов в eShopOnContainers реализует явное сопоставление и конфигурацию, когда это необходимо, как показано в следующем коде.
Можно задать все сопоставления текучего API в одном и том же методе OnModelCreating , но рекомендуется разбить этот код на несколько классов конфигурации, по одному на сущность, как показано в примере. В первую очередь отдельные классы конфигурации для настройки разных типов сущностей рекомендуется использовать для больших моделей.
В примере кода показано несколько явных объявлений и сопоставлений. Однако соглашения EF Core выполняют многие из этих сопоставлений автоматически, так что фактический код, который понадобится в вашем случае, может иметь меньший размер.
Реализация пользовательских репозиториев с помощью Entity Framework Core
На уровне реализации репозиторий является просто классом с кодом сохраняемости данных, координируемым единицей работы (DBContext в EF Core) при выполнении обновлений, как показано в следующем классе:
Интерфейс IBuyerRepository поступает из уровня модели предметной области как контракт. Однако реализация репозитория выполняется на уровне сохраняемости и инфраструктуры.
Алгоритм Hi/Lo в EF Core
Интересным аспектом кода в предыдущем примере является применение алгоритма Hi/Lo в качестве стратегии создания ключей.
Алгоритм Hi/Lo удобно использовать в тех случаях, когда требуются уникальные ключи перед фиксацией изменений. Вкратце, алгоритм Hi-Lo присваивает строкам таблицы уникальные идентификаторы, которые не зависят от немедленного сохранения строк в базе данных. Это позволяет начинать использовать идентификаторы сразу, как это происходит с обычными последовательными идентификаторами базы данных.
Алгоритм Hi/Lo описывает механизм для получения пакета уникальных идентификаторов из последовательности связанной базы данных. Эти идентификаторы являются безопасными для использования, так как база данных гарантирует уникальность, исключая конфликты между пользователями. Этот алгоритм представляет интерес по следующим причинам.
Он не нарушает шаблон единицы работы.
Он получает идентификаторы последовательности в пакетах, чтобы свести к минимуму количество обращений к базе данных.
Он создает удобный для восприятия идентификатор, в отличие от методов, в которых используются идентификаторы GUID.
EF Core поддерживает алгоритм HiLo с помощью метода UseHiLo , как показано в предыдущем примере.
Harder to Code, Faster to Execute
Expressing SQL and populating related objects are tasks I’ve let EF handle in the background, so this is definitely more effort to code. But if you’re working with lots of data and runtime performance is important, it can certainly be worth that effort. I have about 30,000 designers in my sample database. Only a few of them have products. I did some simple benchmark tests where I ensured I was comparing apples to apples. Before looking at the test results, there are some important points to understand about how I did these measurements.
Remember that, by default, EF is designed to track objects that are the results of queries. This means it creates additional tracking objects, which involves some effort, and it also needs to interact with those tracking objects. Dapper, in contrast, just dumps results into memory. So it’s important to take EF’s change tracking out of the loop when making any performance comparisons. I do this by defining all my EF queries with the AsNoTracking method. Also, when comparing performance, you need to apply a number of standard benchmark patterns, such as warming up the database, repeating the query many times and throwing out the slowest and fastest times. You can see the details of how I built my benchmarking tests in the sample download. Still, I consider these to be “lightweight” benchmark tests, just to provide an idea of the differences. For serious benchmarks, you’d need to iterate many more times than my 25 (start at 500), and to factor in the performance of the system on which you’re running. I’m running these tests on a laptop using a SQL Server LocalDB instance, so my results are useful only for comparison’s sake.
The times I’m tracking in my tests are for executing the query and building the results. Instantiating connections or DbContexts isn’t counted. The DbContext is reused so the time for EF to build the in-memory model is also not taken into account, as this would only happen once per application instance, not for every query.
Figure 2 shows the “select *” tests for Dapper and the EF LINQ query so you can see the basic construct of my testing pattern. Notice that outside of the actual time gathering, I’m collecting the time for each iteration into a list (called “times”) for further analysis.
Figure 2 Tests to Compare EF and Dapper When Querying All DapperDesigners
There’s one other point to be made about comparing “apples to apples.” Dapper takes in raw SQL. By default, EF queries are expressed with LINQ to EF and must go through some effort to build the SQL for you. Once that SQL is built, even SQL that relies on parameters, it’s cached in the application’s memory so that effort is reduced on repetition. Additionally, EF has the ability to execute queries using raw SQL, so I’ve taken both approaches into account. Figure 3 lists the comparative results of four sets of tests. The download contains even more tests.
Figure 3 Average Time in Milliseconds to Execute a Query and Populate an Object Based on 25 Iterations, Eliminating the Fastest and Slowest
*AsNoTracking queries | Relationship | LINQ to EF* | EF Raw SQL* | Dapper Raw SQL |
All Designers (30K rows) | – | 96 | 98 | 77 |
All Designers with Products (30K rows) | 1 : * | 251 | 107 | 91 |
All Designers with Clients (30K rows) | * : * | 255 | 106 | 63 |
All Designers with Contact (30K rows ) | 1 : 1 | 322 | 122 | 116 |
In the scenarios shown in Figure 3, it’s easy to make a case for using Dapper over LINQ to Entities. But the narrow differences between raw SQL queries may not always justify switching to Dapper for particular tasks in a system where you’re otherwise using EF. Naturally, your own needs will be different and could impact the degree of variation between EF queries and Dapper. However, in a high-traffic system such as Stack Overflow, even the handful of milliseconds saved per query can be critical.
Методы, реализуемые в репозитории (обновления или транзакции по отношению к запросам)
В каждом классе репозитория следует поместить методы сохраняемости, которые обновляют состояние сущностей, содержащихся в связанном с ним агрегате. Помните, что имеется однозначное соответствие между агрегатом и связанным с ним репозиторием. Также учитывайте, что корневой объект сущности агрегата может иметь внедренные дочерние сущности в своем графе EF. Например, покупатель может иметь несколько способов оплаты в виде связанных дочерних сущностей.
Поскольку этот подход для микрослужбы заказов в eShopOnContainers также основан на CQS/CQRS, большинство запросов не реализуется в пользовательских репозиториях. Разработчики имеют право создавать нужные им запросы и соединения для уровня представления данных без ограничений, установленных агрегатами, пользовательскими репозиториями в агрегатах и DDD в целом. Большинство пользовательских репозиториев, предлагаемых в данном руководстве, имеют несколько методов обновления или транзакций, но только те методы запросов, которые необходимы для получения обновляемых данных. Например, репозиторий BuyerRepository реализует метод FindAsync, так как приложению нужно узнать, существует ли конкретный покупатель, прежде чем создавать нового покупателя, связанного с заказом.
Однако реальные методы запросов для получения данных для отправки на уровень представления данных или в клиентские приложения реализуются, как было указано, в запросах CQRS на основе гибких запросов с помощью Dapper.
So, Finally, I Looked at Dapper. What Do I Think?
And what about me? I regret not taking the time to look at Dapper earlier and am happy I’ve finally done so. I’ve always recommended AsNoTracking or using views or procedures in the database to alleviate performance problems. This has never failed me or my clients. But now I know I have another trick up my sleeve to recommend to developers who are interested in squeezing even more performance out of their systems that use EF. It’s not a shoo-in, as we say. My recommendation will be to explore Dapper, measure the performance difference (at scale) and find a balance between performance and ease of coding. Consider StackOverflow’s obvious use: querying questions, comments and answers, then returning graphs of one question with its comments and answers along with some metadata (edits) and user info. They’re doing the same types of queries and mapping out the same shape of results over and over again. Dapper is designed to shine with this type of repetitive querying, getting smarter and faster each time. Even if you don’t have a system with the insane number of transactions that Dapper was designed for, you’re likely to find that a hybrid solution gives you just what you need.
Thanks to the following Stack Overflow technical experts for reviewing this article: Nick Craver and Marc Gravell
Nick Craver (@Nick_Craver) is a Developer, Site Reliability Engineer, and sometimes DBA for Stack Overflow. He specializes in performance tuning in all layers, overall system architecture, data center hardware, and maintaining many open source projects such as Opserver.
При использовании реляционных баз данных, таких как SQL Server, Oracle или PostgreSQL, рекомендуемый подход заключается в реализации уровня сохраняемости на основе Entity Framework (EF). EF поддерживает LINQ и предоставляет строго типизированные объекты для вашей модели, а также упрощенную сохраняемость в базу данных.
Dapper in a Nutshell
Figure 1 DapperDesigner Class
The project where I’m executing queries has a reference to Dapper, which I retrieve via NuGet (install-package dapper). Here’s a sample call from Dapper to execute a query for all the rows in the DapperDesigners table:
Note that for code listings in this article, I’m using select * rather than explicitly projecting columns for queries when I want all columns from a table. sqlConn is an existing SqlConnection object that I’ve already instantiated, along with its connection string, but haven’t opened.
The Query method is an extension method provided by Dapper. When this line executes, Dapper opens the connection, creates a DbCommand, executes the query exactly as I wrote it, instantiates a DapperDesigner object for each row in the results and pushes the values from the query results into the properties of the objects. Dapper can match the result values with properties by means of a few patterns even if the property names don’t match the column names and even if the properties aren’t in the same order as the matching columns. It can’t read minds, though, so don’t expect it to figure out mappings involving, for example, numerous string values where the orders or names of the columns and properties are out of sync. I did try a few odd experiments with it to see how it would respond and there are also global settings that control how Dapper can infer mappings.
Применение пользовательского репозитория по сравнению с непосредственным применением DbContext EF
Однако реализация пользовательских репозиториев обеспечивает определенные преимущества при реализации более сложных микрослужб или приложений. Шаблоны Unit of Work и Repository предназначены для инкапсуляции уровня сохраняемости инфраструктуры, поэтому он отделен от уровней приложения и модели предметной области. Реализация этих шаблонов позволяет упростить использование макетов репозиториев, моделирующих доступ к базе данных.
На рис. 7-18 можно увидеть различия между отсутствием использования репозиториев (с применением класса DbContext EF напрямую) и использованием репозиториев, что упрощает макетирование таких репозиториев.
Рис. 7-18. Применение пользовательских репозиториев по сравнению с простым DbContext
На рис. 7-18 показано, что применение пользовательского репозитория добавляет уровень абстракции, который может использоваться для упрощения тестирования путем макетирования репозитория. Существует несколько вариантов макетирования. Можно макетировать только репозитории или макетировать всю единицу работы. Как правило, достаточно макетирования только репозиториев, и сложность абстрагирования и макетирования всей единицы работы обычно не требуется.
Короче говоря, пользовательские репозитории позволяют упростить тестирование кода с помощью модульных тестов, на которые не влияет состояние уровня данных. Если выполняются тесты, которые также обращаются к реальной базе данных через Entity Framework, то это не модульные тесты, а интеграционные тесты, которые выполняются гораздо медленнее.
Если вы использовали DbContext напрямую, вам потребовалось бы выполнить его макетирование или запуск модульных тестов с помощью SQL Server в памяти с прогнозируемыми данными для модульных тестов. Однако макетирование DbContext или управление фиктивными данными требует больше усилий, чем макетирование на уровне репозитория. Конечно, вы всегда можете тестировать контроллеры MVC.
Время существования экземпляра IUnitOfWork и DbContext EF в контейнере IoC
Режим создания экземпляра DbContext не должен быть настроен как ServiceLifetime.Transient или ServiceLifetime.Singleton.
Dapper and Relational Queries
My DapperDesigner type has a number of relationships. There’s a one-to-many (with Products), a one-to-one (ContactInfo) and many-to-many (Clients). I’ve experimented with executing queries across those relationships, and Dapper can handle the relationships. It’s definitely not as easy as expressing a LINQ to EF query with an Include method or even a projection. My TSQL skills were pushed to the limit, however, because EF has allowed me to become so lazy over the past years.
Here’s an example of querying across the one-to-many relationship using the SQL I would use right in the database:
Notice that the Query method requires I specify both types that must be constructed, as well as indicate the type to be returned—expressed by the final type parameter (DapperDesigner). I use a multi-line lambda to first construct the graphs, adding the relevant products to their parent designer objects, and then to return each designer to the IEnumerable the Query method returns.
The downside of doing this with my best attempt at the SQL is that the results are flattened, just like they’d be with the EF Include method. I’ll get one row per product with designers duplicated. Dapper has a MultiQuery method that can return multiple resultsets. Combined with Dapper’s GridReader, the performance of these queries will definitely outshine EF Includes.
Дополнительные ресурсы
Hybrid Dapper Plus EF in the Real World
There are lots and lots of systems that use Dapper for 100 percent of their data persistence. But recall that my interest was piqued because of developers talking about hybrid solutions. In some cases, these are systems that have EF in place and are looking to tweak particular problem areas. In others, teams have opted to use Dapper for all queries and EF for all saves.
In response to my asking about this on Twitter, I received varied feedback.
@garypochron told me his team was “moving ahead with using Dapper in high call areas & using resource files to maintain org of SQL.” I was surprised to learn that Simon Hughes (@s1monhughes), author of the popular EF Reverse POCO Generator, goes the opposite direction—defaulting to Dapper and using EF for tricky problems. He told me “I use Dapper where possible. If it’s a complex update I use EF.”
Working more directly with the database has other advantages besides performance. Rob Sullivan (@datachomp) and Mike Campbell (@angrypets), both SQL Server experts, love Dapper. Rob points out that you can take advantage of database features that EF doesn’t give access to, such as full text search. In the long run, that particular feature is, indeed, about performance.
On the other hand, there are things you can do with EF that you can’t do with Dapper besides the change tracking. A good example is one I took advantage of when building the solution I created for this article—the ability to migrate your database as the model changes using EF Code First Migrations.
Dapper isn’t for everyone, though. @damiangray told me Dapper isn’t an option for his solution because he needs to be able to return IQueryables from one part of his system to another, not actual data. This topic, deferred query execution, has been brought up in Dapper’s GitHub repository at bit.ly/22CJzJl, if you want to read more about it. When designing a hybrid system, using some flavor of Command Query Separation (CQS) where you design separate models for particular types of transactions (something I’m a fan of) is a good path. That way, you aren’t trying to build data access code that’s vanilla enough to work with both EF and Dapper, which often results in sacrificing benefits of each ORM. Just as I was working on this article, Kurt Dowswell published a post called “Dapper, EF and CQS” (bit.ly/1LEjYvA). Handy for me, and handy for you.
Summary
I hope you enjoyed seeing how we do things using the CQS pattern, Dapper, and EF! I think the real key to the success of using mixed ORMs is the CQS pattern. It has helped so much with code base clarity, testing, and maintainability. I would love to hear your feedback positive or negative! Please check me out on twitter at @kurtdowswell Thanks again for checking out my post!
Дополнительные ресурсы
Время существования экземпляра репозитория в контейнере IoC
Аналогичным образом время существования репозитория обычно должно быть задано как scoped — ограниченное областью (InstancePerLifetimeScope в Autofac). Оно также может быть задано как transient — временное (InstancePerDependency в Autofac), но служба будет более эффективной в отношении памяти при использовании времени существования, ограниченного областью.
Использование для репозитория времени существования singleton может вызвать серьезные проблемы с параллелизмом, если для DbContext установлено время существования scoped (InstancePerLifetimeScope) (время существования по умолчанию для DBContext).
Thanks for reading. If you found this article useful, feel free to hit that clap button 👏 to help others find it.
Update (6/18/2019):
I am currently using both Entity Framework Core and Dapper in my current project. Entity Framework for insert, update, and get. And Dapper for complex queries like reports, joins (where the data is fetched from multiple tables). Entity Framework is reducing my development time and dapper is fetching complex data with more speed. Now i also have more control and flexibility and can decide where to use what. Now i believe that nothing works better than the combination of Entity Framework and Dapper!
After talking with some people outside of the company I work for, I’ve been wanting to explain the reasons why we have chosen to use a Dapper and Entity Framework hybrid approach for our back-end Command–query separation (CQS) classes.
Raw SQL via EF is a very possible solution we considered, but seeing the performance results from various sources nudged us to try Dapper. Given the structure of our queries, it made little difference to use Dapper. So benefiting from the advantages of Dapper’s speed made sense to us.
Here is the overview of the implementation we are using and some explanations of how we got there!
The Command-Query separation structure has been a great progression for the code bases I work on from a more traditional service/repository layered structure. Using CQS, it has allowed our large code bases to be more SOLID and to be much more testable do to the modular design of the code.
In the CQS structure instead of having a service with all of the CRUD operations on an entity, we have a single responsibility class, called a handler, to do each of the actions needed on that entity.
Lets look at some code from one of our queries!
Here you see the class header for the query handler, indicating the query it receives and the data it returns. We are using MediatR to simplify our calls to our queries and commands.
Next are the class properties, here we have the IDbExecutor interface that allows for unit tests to be ran against the query if desired. In the end I went with integration tests to validate the structure of the SQL was well formed (more on that later). The DynamicParameters are used for… you guessed it! SQL Parameters. This is a Dapper class that allows for safe parameterization. The Sql property hosts the raw SQL query we will be executing. Notice the line. This is where we will inject our where clause into the SQL statement.
Ok, now we are getting somewhere! Here is the Query Handler function. This receives a query parameter and executes that query against the database. The first line you will see we are adding the where clause to the SQL I explain the advantanges of dyanamic where clauses below. The second line shows the DapperWrapper class executing the query and casting the result to our query result object.
This method injects the where clause into the SQL statement at the . Notice from the SQL statement above we have WHERE 1=1 and then the . This is nice so that we can always simple append an AND statement to the clause. One big advantage of doing dynamic where clauses is performance on table indexes. In the past we have used something like this:
This approach does not take advantage of any indexing that might be applied to the column being compared. MUCH more on this can be found here! But in summary, the only way for the above SQL Where clause to utilize indexes is to OPTION (RECOMPILE). But if you have a lot of reads on that query, you could put a high amount of strain on your server recompiling the query for each execution.
Dynamic where clauses bring a larger chance for SQL structure errors, so testing becomes all the more important… If it wasn’t already using raw SQL! So that leads me to how to test this class!
Сопоставление таблиц
Сопоставление таблиц определяет таблицы, данные которых должны запрашиваться и сохраняться в базе данных. Ранее было показано, как сущности предметной области (например, предметная область продуктов или заказов) могут использоваться для создания схемы связанной базы данных. Технология EF строго построена на концепции соглашений. Соглашения рассматривают такие вопросы, как "Что будет называться таблица?" или "Какое свойство является первичным ключом?" Соглашения обычно основаны на обычных именах. Например, первичный ключ обычно является свойством, которое заканчивается на Id .
По соглашению каждая сущность будет настроена для сопоставления с таблицей с именем, указанным в свойстве DbSet , которое предоставляет сущность в производном контексте. Если для конкретной сущности значение свойства DbSet не задано, то используется имя класса.
Заметки к данным и текучий API
Существует множество дополнительных соглашений EF Core, и большинство из них можно изменить с помощью заметок к данным или текучего API, реализованного в методе OnModelCreating.
Заметки к данным необходимо использовать в самих классах модели сущностей, что является более навязчивым способом с точки зрения DDD. Это связано с тем, что вы засоряете модель заметками к данным, относящимися к базе данных инфраструктуры. С другой стороны, текучий API представляет удобный способ изменения большинства соглашений и сопоставлений на уровне инфраструктуры сохраняемости данных; таким образом, модель сущностей будет чистой и отделенной от инфраструктуры сохраняемости.
1 Answer 1
- Does anyone have any updates on performance regarding EF 6.1.x? This concerns general queries made within a DbContext?
Ans: I don't have specific numbers, but I have updated the performance rig to EF6; I can't remember the outcome exactly, but: EF6 is a lot faster than EF-old, but dapper is still significantly faster in many scenarios (and about the same for the edge-cases)
- I suppose I cannot use nicely formatted LINQ queries with Dapper. Do you have experience with that? Is it worth losing LINQ for the additional speed?
Ans: That is subjective; for us: yes, absolutely worth it - but we care lots about speed. Parsing expression trees has impact, and generated SQL is very rarely in the same league as handcrafted SQL by a decent dev
- IS Dapper still under active, constant development? GitHub tells me yes, but as with Subsonic, that can change rather quickly?
Ans: Absolutely; I think I've deployed about 4 versions this month.
- Is it feasable/doable to mix Dapper and EF? Dapper when we need the speed, otherwise EF?
Ans: Yes, you can do that; that is how we started with dapper - we used that to replace LINQ to SQL code that was causing performance problems; over time, that had grown, and now we have very little LINQ to SQL code remaining (but still some)
After reading numerous articles and blog posts, chatting with developers and playing a bit with Dapper, I wanted to share my discoveries with you, especially with those who, like me, perhaps heard of Dapper, but don’t really know what it is or how it works—or why people love it. Keep in mind that I am in no way an expert. Rather, I know enough to satisfy my curiosity for the time being, and hopefully spark your interest so you’ll dig even further.
Знакомство с Entity Framework Core
Поскольку общие сведения о EF Core уже доступны в документации Майкрософт, здесь будут просто приведены ссылки на эту информацию.
Dapper and EF for Other Persistence Needs
So far I’ve measured simple queries where I just pulled back all columns from a table that exactly matched properties of the types being returned. What about if you’re projecting queries into types? As long as the schema of the results matches the type, Dapper sees no difference in creating the objects. EF, however, has to work harder if the results of the projection don’t align with a type that’s part of the model.
The DapperDesignerContext has a DbSet for the DapperDesigner type. I have another type in my system called MiniDesigner that has a subset of DapperDesigner properties:
MiniDesigner isn’t part of my EF data model, so DapperDesignerContext has no knowledge of this type. I found that querying all 30,000 rows and projecting into 30,000 MiniDesigner objects was 25 percent faster with Dapper than with EF using raw SQL. Again, I recommend doing your own performance profiling to make decisions for your own system.
Dapper can also be used to push data into the database with methods that allow you to identify which properties must be used for the parameters specified by the command, whether you’re using a raw INSERT or UPDATE command or you’re executing a function or stored procedure on the database. I did not do any performance comparisons for these tasks.
Сопоставление полей вместо свойств
Эта функция, появившаяся в EF Core 1.1, позволяет сопоставлять столбцы с полями напрямую. Теперь существует возможность не использовать свойства в классе сущностей, а просто сопоставлять столбцы таблицы с полями. Эта возможность часто используется в закрытых полях для хранения внутреннего состояния, доступ к которому не должен осуществляться извне сущности.
Это можно делать как с отдельными полями, так и с коллекциями, например с List<> . Этот момент упоминался ранее, когда мы обсуждали моделирование классов модели предметной области, но здесь можно видеть, как это сопоставление выполняется для конфигурации PropertyAccessMode.Field , выделенной в предыдущем коде.
Читайте также: