EntityFramework用法和常见问题
优化建议
- 尽可能把操作放在server端(数据库)
- 把数据获取到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();
}
}