使用AutoMapper查找相关对象并将其添加为属性
本文关键字:添加 属性 对象 AutoMapper 查找 使用 | 更新日期: 2023-09-27 18:14:27
我有一个运行在Entity Framework 6, Model First
上的应用程序,运行在一个遗留数据库上。
在应用程序中,我们有一个Person
对象,它有一个或多个Address
对象。它们使用一个额外的标签链接:PersonXAddress
,如下所示:
Person
Id
Name
...
PersonXAddress
PersonId
AddressId
Address
Id
Street
PostalCode
...
使用AutoMapper
,我已经添加了一个属性到我的PersonDto"HomeAddres",这是AddressType == 1
的地址,像这样:
Mapper.CreateMap<Person, PersonDto>()
.ForMember(x => x.HomeAddress,
o => o.MapFrom(y => y.PersonXAddresses
.Where(a => a.Address.AddressTypeId == 1)
.Select(x => x.Address).FirstOrDefault();
所以在我的代码中,我永远不需要遍历所有不同的地址来找到那个人的HomeAddress。
但是,我发现这是非常缓慢的。它创建了一个巨大的sql查询(大约50行sql),第一次运行这个查询可能需要30秒。在第一次触发它之后,查询从数据库中获取一些Person对象可能需要大约1秒钟的时间。我发现,如果我注释掉上面的映射,生成的查询将在不到一秒的时间内启动,并在几毫秒内返回结果。
是否有更好的方法自动查找家庭住址?你能在我需要改进的地方给我一些帮助吗?
Thanks to lot
你看起来有一个建模问题。在Person模型(和数据库表)上应该有一个HomeAddress。你在LINQ查询中假设有零个或一个家庭地址。只需在数据库级别显式地建模。
试试用LINQ:
var personDTO = context.Person
.Where(p => p.Id == 1)
.Select(p => new {
person = p,
homeAddress = p.PersonXAddresses
.FirstOrDefault(px => px.Address.AddressTypeID == 1)
.Address })
.Select(pd > new PersonDto {
Id = person.Id
Name = person.Name,
...
HomeAddress = homeAddress
}).ToList();
同时,确保你有适当的索引(AddressTypeID等)。
现在可以使用AutoMapper Queryable extensions库中的AutoMapper ProjectTo<>
扩展来解决这个问题。
您的查询现在可以看起来像这样(使用EF Plus IncludeFilter
扩展为方便,并假设您的EF模式已经抽象掉了交叉引用表):
context.Persons
.IncludeFilter(p => p.Addresses.Where(a => a.AddressTypeId == 1))
.ProjectTo<PersonDTO>();
你的地图应该是这样的:
Mapper.CreateMap<Person, PersonDTO>()
.ForMember(x => x.HomeAddress,
o => o.MapFrom(y => y.Addresses.FirstOrDefault()));
使用ProjectTo<>
扩展的优点是,对数据库本身的查询将只包括映射所需的字段,从而避免了过度订阅问题。与往常一样,请确保为表连接建立索引,以提高性能。