1.项目场景:
项目场景:
1.本项目采用了EF架构来建立实体与实体之间的关联关系。
2.一个部门对应多个摄像头
1.部门实体:
public partial class DepartmentEntity //部门实体
{
public int Id { get; set; }
public virtual ICollection< CameraEntity> lstCamera { get; set; }
/// <summary>
/// 部门编码
/// </summary>
public string DeptCode { get; set; }
/// <summary>
/// 部门名称
/// </summary>
public string DeptName { get; set; }
/// <summary>
/// 经度
/// </summary>
[DecimalPrecision(16, 8)]
public decimal? Lon { get; set; }
/// <summary>
/// 纬度
/// </summary>
[DecimalPrecision(16, 8)]
public decimal? Lat { get; set; }
}
2.摄像头实体:
public class CameraEntity //摄像头实体
{
public int Id { get; set; }
/// <summary>
/// 摄像头名称
/// </summary>
public string CameraName { get; set; }
/// <summary>
/// 所属部门Id
/// </summary>
public int? DeptId { get; set; }
public virtual DepartmentEntity dept { get; set; }
/// <summary>
/// 经度
/// </summary>
[DecimalPrecision(16, 8)]
public decimal? Lng { get; set; }
/// <summary>
/// 纬度
/// </summary>
[DecimalPrecision(16, 8)]
public decimal? Lat { get; set; }
}
1.部门 mapping:
public class DepartmentEntityMapping : DataEntityTypeConfiguration<DepartmentEntity>
{
public DepartmentEntityMapping()
{
//部门表
ToTable("Department");
HasKey(t => t.Id);
//一对多
HasMany(x => x.lstCamera).WithOptional(z => z.dept).HasForeignKey(y=>y.DeptId);
}
}
2.摄像头 mapping:
public class CameraEntityMapping : DataEntityTypeConfiguration<CameraEntity>
{
public CameraEntityMapping()
{
//AssetCameraInfo为数据库表名
ToTable("AssetCameraInfo");
HasKey(t => t.Id);
//一对多
HasOptional(x => x.dept).WithMany().HasForeignKey(x => x.DeptId);
}
}
1.controller层 – 调用该接口报错 – error:出现循环调用
/// <summary>
/// 查摄像头集合
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[Route("TmpTest")]
[HttpPost]
[AllowAnonymous]
public IHttpActionResult TmpTest([FromBody] QuerCameraInfo model)
{
TipsModel<List<CameraEntity>> tips = new TipsModel<List<CameraEntity>>(false);
var lst = new AssetCameraInfoServiceV2().GetList(model);
tips.SetResult(true, lst, "success");
return Json(tips);
}
2.Service层
public partial class AssetCameraInfoServiceV2
{
readonly Repository<CameraEntity> dao = new Repository<CameraEntity>();
private IQueryable<BMS_D_AssetCameraInfoEntity> QueryCmd(QuerCameraInfo where)
{
var query = dao.Table;
query = query.Where(x => x.DeleteState == 0);
if (!where.CameraName.IsEmpty())
query = query.Where(x => x.CameraName.Contains(where.CameraName));
if (!where.DeptId.IsEmpty())
query = query.Where(x => x.DeptId == where.DeptId);
return query;
}
public List<CameraEntity> GetList(QuerCameraInfo where)
{
var temp = QueryCmd(where);
return temp.ToList();
}
}
3.model 传参QuerCameraInfo
public class QuerCameraInfo
{
public int Id { get; set; }
/// <summary>
/// 摄像头名称
/// </summary>
public string CameraName { get; set; }
/// <summary>
/// 摄像头编码
/// </summary>
public string CameraCode { get; set; }
/// <summary>
/// 所属部门Id
/// </summary>
public int? DeptId { get; set; }
public virtual DepartmentEntity dept { get; set; }
}
2.报错内容
1.调用 controller层 的接口 TmpTest 报错如下:
"StatusCode": 408,
"OperateTime": "2022-09-08T14:56:58.9725345+08:00",
"Message": "2022年9月8日\tSelf referencing loop detected with type 'System.Data.Entity.DynamicProxies.BMS_D_AssetCameraInf_6940526873A10F06EF9B905552C9F9854FEA9BBA8CFBCCDBD1E36BF810A687E9'. Path 'ReturnValue[7].dept.lstCamera'.\t\n"
3.原因分析:
通过 GetList() 获得的 lst 集合中,每个相机实体中都有一个部门实体,每个部门中又有相机集合,故而出现死循环。
4.解决方案:
将 lst 转换为 model
1.controller层 – 分页查询camera
/// <summary>
/// 查询摄像头信息(分页)
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[Route("GetListCameraInfo")]
[HttpPost]
[AllowAnonymous]
public IHttpActionResult GetListCameraInfo([JsonBinder] ElGrid grid)
{
TipsModel<ElGrid> tips = new TipsModel<ElGrid>(false);
var where = grid.CreatePageBase<QuerCameraInfo>();
AssetCameraInfoServiceV2 serveice = new AssetCameraInfoServiceV2();
//转model
tips.ReturnValue = grid.SetData(serveice.GetPageList(where), x => x.Select(y => y.ToModel()));
//转model,model比entity多一个deptName字段
tips.ReturnValue = grid.SetData(serveice.GetPageList(where), x => x.Select(y => y.ToInfoModel()));
tips.IsSuccess = true;
return Json(tips);
}
5.补充信息
每个 AutoMapper 都对应一个 Profile
1.CameraInfoModel
public class CameraInfoModel
{
public int Id { get; set; }
/// <summary>
/// 摄像头名称
/// </summary>
public string CameraName { get; set; }
/// <summary>
/// 所属部门Id
/// </summary>
public int? DeptId { get; set; }
/// <summary>
/// 部门名称
/// </summary>
public string DeptName { get; set; }
/// <summary>
/// 经度
/// </summary>
[DecimalPrecision(16, 8)]
public decimal? Lng { get; set; }
/// <summary>
/// 纬度
/// </summary>
[DecimalPrecision(16, 8)]
public decimal? Lat { get; set; }
}
- AutoMapperExcetions 中的 CameraMapper
#region 摄像头信息表 CameraEntity
public static CameraInfoModel ToInfoModel(this CameraEntity entity)
{
return entity.MapTo<CameraEntity, CameraInfoModel>();
}
public static CameraEntity ToInfoEntity(this CameraInfoModel model)
{
return model.MapTo<CameraInfoModel, CameraEntity>();
}
#endregion
3.CameraProfile.cs
将 entity 转换为 CameraInfoModel, 其中根据 deptId 获取部门名称放在 CameraInfoModel 中进行输出.
private void CameraProfile() {
CreateMap<CameraInfoModel, CameraEntity>();
CreateMap<CameraEntity, CameraInfoModel>()
.ForMember(x => x.DeptName, y => y.MapFrom(z => z.dept == null ? "" : z.dept.DeptName));
}