首页 > 技术文章 > EntityFramework用法和常见问题

woncode 2020-06-04 10:42 原文

优化建议

  1. 尽可能把操作放在server端(数据库)
  2. 把数据获取到client端(应用程序)时,只选择所需的字段。如select,减少内存的使用,增加性能

复杂查询

Predicate

Predicate就是linq的一个Expression对象,代表一个检索条件,返回值为bool值,true代表获取记录,false则不获取。使用And和Or方法把多个查询串联,判断机制为从左到右,串联后两者合并为一个检索结果,再继续和其他语句串联

除了直接串联一个返回值为bool值得表达式,还可以串联另一个Predicate对象

创建:传入一个初始bool值,代表默认检索调试,即初始返回值。如无其他串联语句,当初始值为true时,相当于获取所有记录,为false时,相当于获取空记录

var predicate = PredicateBuilder.New<T>(true);

Linq多表联查和分页

根据筛选字段所在的表,先各自进行条件筛选,并根据主表做分页,最后再用join关键字联合查询

var subpackageQuery = _subpackageRepository.GetAll().Where(s => s.IsDeal.Equals(1)).PageBy(input);
var tranQuery = Repository.GetAll();
var query = from subpackage in subpackageQuery
            join tran in tranQuery on subpackage.TranId equals tran.Id
            select new GetTranDto
            {
                VarietyName = subpackage.VarietyName,
                BuyerName = tran.BuyerName,
                TranDate = subpackage.TranDate
            };

多表联查join后再group:join后先select,然后再group,若直接group,不仅容易出错,而且需使用两次into,代码繁乱,不易理解

// 坏例子
query = from entrance in query
        join access in _internalAccessRepository.GetAll() on entrance equals access.Xgh into joinAccess
        from j2 in joinAccess.DefaultIfEmpty()
        group j2 by j2.Department into grouped
        select new WelcomeStatisticItem
        {
            DepartmentName = grouped.Key,
            RegistedCount = grouped.Count()
        };

// 好例子
selectQuery = from entrance in _entranceRegRepository.GetAll()
              join access in _internalAccessRepository.GetAll() on entrance equals access.Xgh
              select new
              {
                  Xgh = entrance,
                  Department = access.Department
              };
groupQuery = from entrance in query
             group entrance by entrance.Department into grouped
             select new WelcomeStatisticItem
             {
                 DepartmentName = grouped.Key,
                 RegistedCount = grouped.Count()
             };

常见问题

The LINQ expression could not be translated

所写的linq表达式无法转化为SQL语句,一般原因是在linq中调用了本地(client)的方法,从而使得在数据库端(Server)无法完成调用

Client side XXX is not supported

XXX操作不支持在Client端执行,可在XX操作之后加上select操作来解决

Missing type map configuration or unsupported mapping

把Dto中的AutoMapFrom特性改为AutoMap

使用MySQL8时可能会遇到Tls版本不一致,无法连接的问题

更新后无法及时获取

在一个请求中,如果使用Repository.Update方法更新实体记录,再用Repository.Get获取实体,获取的数据是未更新前的记录。即使开启事务也不生效

规避方法:不适应EF的code first,而是使用手写sql的方式更新记录

//[UnitOfWork]
[UnitOfWork(IsDisabled = true)]
public void UpdateRemaininAmount(PlantSubpackageCreateInput input)
{
    using (var unitOfWork = _unitOfWorkManager.Begin())
    {
        var plantHarvest = _plantHarvestRepository.Single(p => p.HarvestId.Equals(input.HarvestId));
        if (input.SubpackageType == 1)
        {
            plantHarvest.RemainingPackageWeight -= input.SubpackageTotal;
        }
        else
        {
            plantHarvest.RemainingPackageAmount -= input.SubpackageTotal;
        }
        _plantHarvestRepository.Update(plantHarvest);
        _unitOfWorkManager.Current.SaveChanges();
        unitOfWork.Complete();
    }
}

推荐阅读