vs c# ef core_使用EF Core和C#的简单实用的规范模式

vs c# ef core

抽象 (Abstract)

Here I address how to implement specification pattern in C#. The key to more efficiency is to use lambda expressions and watch for client evaluation.

在这里,我介绍了如何在C#中实现规范模式。 提高效率的关键是使用lambda表达式并注意客户评估。

实施规范 (Implementing specifications)

In this article, I described a hotel booking system and its components. Also, here I explained how the specification pattern improved that architecture. In the current story, I will address how to implement a query handler which utilises this pattern. The framework of choice is EF Core and the language is C#.

本文中 ,我介绍了酒店预订系统及其组件。 另外,我在这里解释了规范模式如何改进了该体系结构。 在当前的故事中,我将介绍如何实现利用此模式的查询处理程序。 选择的框架是EF Core,语言是C#。

The main part of the specification pattern is an abstract specification class. Let’s see how we can implement that using C#.

规范模式的主要部分是抽象规范类。 让我们看看如何使用C#来实现。

namespace HotelBookingSystem.BookingRegistry {
 public abstract class Specification {
   abstract bool IsSatisfiedBy(BookingRecord b);
 }
}

Now let’s see how the query handler looks like in C#.

现在,让我们看看查询处理程序在C#中的外观。

namespace HotelBookingSystem.BookingRegistry {
  public Class BookingRegisteryQueryHandler: IBookingRegisteryQueryHandler {
    private readonly BookingRecordContext context;
        public BookingRegisteryQueryHandler(BookingRecordContext context) {
            this.context = context;
        }
    IEnumerable<BookingRecord> GetBookingRecordsBySpecification(Specification spedification) {
     return context.BookingRecords
            .Where(b => spedification.IsSatisfiedBy(b))
            .ToList();
   }
  }
}

As you can see in the above code snippet “GetBookingBySpecification” method is calling the main method of a specification inside the where clause. To try this we can use the following class which specifies all of the bookings in the finished state.

如您在上面的代码片段中看到的,“ GetBookingBySpecification”方法正在where子句中调用规范的main方法。 要尝试此操作,我们可以使用以下类来指定所有处于完成状态的预订。

namespace HotelBookingSystem.BookingAmendments {
    public class FinishedBookingSpecification : Specification {
        public override bool IsSatisfiedBy(BookingRecord bookingRecord) {
            return bookingRecord.Status == BookingRecordStatus.Finished;
        }
    }
}

As expected the query handler would return all of the finished bookings.

如预期的那样,查询处理程序将返回所有已完成的预订。

查询性能问题 (Query performance concerns)

We are using Entity Framework. It would translate Linq queries into SQL queries. If we turn on query logging we can see the generated query for the “FinishedBookingSpecification” looks like this.

我们正在使用实体框架。 它将把Linq查询转换成SQL查询。 如果打开查询日志记录,我们可以看到为“ FinishedBookingSpecification”生成的查询如下所示。

SELECT b.Id, b.Status,...
FROM bookingrecord AS b

Surprisingly we can see it is missing the “Where” condition. The reason is EF has a limitation in converting Linq queries into SQL queries. EF would run the rest of the query in memory. It is called client evaluation. This query is inefficient and as the application scales up would be an issue. Let’s see how we can improve this in the next section.

令人惊讶的是,我们可以看到它缺少“ Where”条件。 原因是EF在将Linq查询转换为SQL查询方面有局限性。 EF将在内存中运行其余查询。 这就是所谓的客户评估 。 该查询效率低下,并且随着应用程序的扩展,将成为一个问题。 让我们在下一部分中看到如何改进它。

使用lambda表达式 (Using lambda expressions)

C# has lambda expressions which if used inside a Linq query can be translated into SQL queries. Let’ see how abstract specification looks like with lambda expressions.

C#具有lambda表达式,如果在Linq查询中使用该表达式,则可以将其转换为SQL查询。 让我们来看一下lambda表达式的抽象规范。

namespace HotelBookingSystem.BookingRegistry {
    public abstract class ExpressionSpecification {
        public Expression<Func<BookingRecord, bool>> Expression { get; set; }        
    }
}

Let’s also reimplement the “FinishedBookingSpecification” using lambda expressions.

我们还使用lambda表达式重新实现“ FinishedBookingSpecification”。

using HotelBookingSystem.BookingRegistry;


namespace HotelBookingSystem.BookingAmendments {
    public class FinishedBookingSpecification : Specification {
        public FinishedBookingSpecification() {
            this.Expression = bookingRecord => 
                bookingRecord.Status == BookingRecordStatus.Finished;
        }
    }
}

And here is how we need to change the query handler class.

这就是我们需要更改查询处理程序类的方式。

namespace HotelBookingSystem.BookingRegistry {
    public class BookingRegisteryQueryHandler : IBookingRegisteryQueryHandler {
        private readonly BookingRecordContext context;


        public BookingRegisteryQueryHandler(BookingRecordContext context) {
            this.context = context;
        }
        public IEnumerable<BookingRecord> GetBookingRecordsBySpecification(Specification spedification) {
             return context.BookingRecords
                .Where(spedification.Expression)
                .ToList();
        }
    }
}

Finally, if we run the query and look into the generated result we see this.

最后,如果我们运行查询并查看生成的结果,我们将看到此情况。

SELECT b.Id, b.Status,...
FROM bookingrecord AS b
WHERE b.status = 0

We have achieved the SQL query we were looking for.

我们已经实现了所需SQL查询。

客户评估 (Client Evaluation)

EF Core before version 2.2 does client evaluation which needs closer attention. When writing an expression in the specification pattern if the performance of the query matters, there is a way mentioned in this article to avoid client evaluation or at least throw an exception. Having said that, in the later versions the exception would be thrown by default.

2.2版之前的EF Core会进行客户评估,需要密切注意。 当写在规范模式的表达式如果查询事项的性能,有这中提到的方式的文章 ,以避免客户评价,或至少抛出异常。 话虽如此,在更高版本中,默认情况下会引发异常。

结论与讨论 (Conclusion and Discussion)

Using lambda expressions in C# would help with implementing more efficient specifications. However, you need to be mindful of client evaluation.

在C#中使用lambda表达式将有助于实现更有效的规范。 但是,您需要注意客户评估。

Working with any framework is sensitive to the type of the framework and its version. Any clever developer needs to always be aware of the limitations of the framework in hand. EF is not an exception, Make sure you know which version you are using and you have reviewed the documentation.

使用任何框架都对框架的类型及其版本敏感。 任何聪明的开发人员都需要始终了解框架的局限性。 EF也不例外,请确保您知道使用的是哪个版本,并且已阅读了文档。

翻译自: https://medium.com/dev-genius/simple-and-practical-specification-pattern-with-ef-core-and-c-997ddd1a0b67

vs c# ef core

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值