Custom paging Effect Based on Entity Framework, entityframework
Introduction
Previously, I wrote a Dapper-based paging implementation. Now I want to write a paging implementation based on Entity Framework and a general implementation of addition, deletion, and modification.
Code
Or first code: https://github.com/jinweijie/EF.GenericRepository
Running examples
Or as before:
1. First clone下 code, decompress database.7z in Database
2. Attach to SQL Server LocalDB. If you are not using LocalDB of SQL Server, you need to change the connection string in App. Config.
3. Press Ctrl + F5 to run the sample program.
Repository base class-Query
Common \ javasactrepository. cs is the base class of Repository. It implements addition, deletion, modification, and query methods, for example:
public virtual Tuple<IEnumerable<T>, int> Find(Expression<Func<T, bool>> criteria , int pageIndex , int pageSize , string[] asc , string[] desc , params Expression<Func<T, object>>[] includeProperties)
This method is one of the AbstractRepository query methods for customizing paging queries. criteria is an expression used as the query condition. The parameters pageIndex, pageSize, asc, and desc are paging-related parameters;
About multiple tables (associated tables ):
IncludeProperties is the joined table when multiple tables exist. Because EF is Lazy Loading by default and associated tables are not loaded immediately by default, sometimes if you write code carelessly, it is possible to query n word tables cyclically in the for loop. You can join the joined table during the query by using the includeProperties parameter.
Repository base class-add, delete, and modify
AbstractRepository has implemented the add, delete, and modify method with the generic type:
Public virtual T Create (T entity)
Public virtual T Update (T entity)
Public virtual T CreateOrUpdate (T entity)
Public virtual void Delete (TId id)
In addition, for the implementation of transaction, I use the Unit of Work mode. Multiple Repository share a DBContext. For details about UOW, refer to Common \ UnitOfWork. cs.
When calling UOW, it is basically similar to the following:
var uow = new EFUnitOfWork();var repo = uow.GetLogRepository();repo.Create(new Log{ LevelId = 1, Thread = "", Location = "Manual Creation", Message = "This is manually created log.", CreateTime = DateTimeOffset.Now, Date = DateTime.Now});uow.Commit();
Obtain one or more Repository from UnitOfWork, share the DBContext, perform addition, deletion, and modification operations, and finally uow unified SaveChanges.
Derived class of Repository
Because AbstractRepository is already available and many methods for adding, deleting, modifying, and querying are implemented, the derived classes, such as the LogRepository In the example project, can basically become very simple and mainly implement some specific business logic, in the example project, because there is no special business logic, it is very simple:
public class LogRepository : AbstractRepository<Log, int> { public LogRepository(EFContext context) : base(context) { } }
Generation of Entity
I prefer Database First implementation. First design the Database and then use edmx reverse engineering to generate POCO. See related files in the Entity directory.
Of course, if you like Code First, there is no problem and it still applies to the implementation in this article.
Tracing ef SQL using Logging logs
When using Entity Framework, it is best to take a look at the SQL statements generated by EF, so that some potential performance problems can be found in the development stage, so as not to be overwhelmed in the production environment :)
In Common \ EFContext. cs, there is a configuration item EnableTraceSql. If it is true, the SQL statement generated by EF will be recorded by nlog. I configure the nlog log to the database. That is to say, when you run the sample project, a new log record will be added for each query. The content is the SQL statement generated during the query:
Specification Pattern
In the query method, there is a overload that accepts an ISpecification example. This implementation can effectively control the business logic. For interfaces called by others, the query parameters can be determined explicitly, for example:
public class LogSearchSpecification : ISpecification<Log> { public string LevelName { get; set; } public string Message { get; set; } public Expression<Func<Log, bool>> ToExpression() { return log => (log.Level.Name == LevelName || LevelName == "") && (log.Message.Contains(Message) || Message == ""); } public bool IsSatisfiedBy(Log entity) { return (entity.Level.Name == LevelName || LevelName == "") && (entity.Message.Contains(Message) || Message == ""); } }
Then, the code that calls this query method clearly knows that my query conditions are LevelName and Message, and that LevelName is equal to and Message is Like, which is implemented in LogSearchSpeficiation, good encapsulation.
Last
This set of implementation has been accumulated over the past few years and has been practiced. Therefore, it can be used as a reference. Of course, in a specific project, you can use some DI to obtain Repository, it is not in the scope of this article. You can do it as you wish. Thank you.