Automapper ProjectTo<>() 在源中使用 NotMapped/Computed 属性 映射到目标时出现问题
Automapper ProjectTo<>() issue when using NotMapped/Computed property in Source to map in destination
我只在使用 ProjectTo 时收到错误,我无法理解根本问题。 (Automapper 版本我使用的是 4.2.1.0)
“LINQ to Entities 不支持指定的类型成员 'Tags'。
仅支持初始值设定项、实体成员和实体导航属性。"
我们也可以在 DTO 中进行这种操作,但我应该坚持只在实体方面进行操作。
请让我知道在不升级版本的情况下我可以处理这个问题的方法或解决方法。 TIA
我希望实体的 Tags 属性 的计算值需要映射到 DTO 的 Tags 属性,但是当我以正常方式进行时这工作正常。
Source/destination 类型
public class Template : IEntity<int>
{
public string Name { get; set; }
public int Id { get; set; }
public string _Tags { get; set; }
[NotMapped]
public List<string> Tags
{
get { return _Tags == null ? null : JsonConvert.DeserializeObject<List<string>>(_Tags); }
set { _Tags = JsonConvert.SerializeObject(value); }
}
}
实体配置
internal sealed class TemplateConfig : EntityTypeConfiguration<Template>
{
public TemplateConfig()
{
Ignore(x => x.Tags);
HasKey(x => x.Id)
.Map(m =>
{
m.ToTable("Template");
m.Property(x => x.Id).HasColumnName("ID");
m.Property(x => x.Name).HasColumnName("Name");
m.Property(x => x._Tags).HasColumnName("Tags");
});
}
}
目标 DTO:
public class Template
{
public int Id { get; set; }
public string Name { get; set; }
public List<string> Tags { get; set; }
}
映射配置
Mapper.CreateMap<Template, DTO.Template>();
Mapper.CreateMap<DTO.Template, Template>();
//These are just for information, but getting error only when using ProjectTo. (Ignore about the OData thing)
public virtual async Task<IQueryable<TDto>> Get(ODataQueryOptions<TDto> query)
{
try
{
var expands = query.GetExpandedPropertyNames();
//Assume the collection has the data from db
var test = Collection.ToList();
//getting the exception here
return await Collection.ProjectTo<TDto>(null, expands).AsTask();
}
catch(Exception ex)
{
throw ex;
}
}
//Controller method
public override async Task<IQueryable<Template>> Get(ODataQueryOptions<Template> query)
{
try
{
List<Template> result = (await base.Get(query)).ToList();
return result.AsEnumerable().AsQueryable();
}
catch(Exception ex)
{
throw ex;
}
}
您是否尝试过在 MappingConfiguration 中实现忽略?我不太清楚你在哪个方向上遇到问题,但类似于:
Mapper.CreateMap<Template, DTO.Template>()
.ForMember(dest => dest.Tags, opts => opts.Ignore());
发生这种情况是因为 .ProjectTo<>(...)
正在 SQL 中为您构建 select 语句。由于 .Tags
在您的对象之间映射,它被包含在 select 语句中,然后 entity framework 抱怨它不能这样做(因为 NotMapped
属性).
而不是使用 ProjectTo<>(...)
你可以只使用普通的 .ToList()
然后使用 .Select(Mapper.Map<TDto>)
或 Mapper.Map<List<TDto>>(list)
.
这应该可行,因为 entity framework 将从字符串字段填充您的标签字段,automapper 可以正常进行映射。
public virtual async Task<IQueryable<TDto>> Get(ODataQueryOptions<TDto> query)
{
try
{
var expands = query.GetExpandedPropertyNames();
//Assume the collection has the data from db
var test = Collection.ToList();
var entities = expands.ToList();
// you can either use .Select to project using LINQ
var dtos = await entities.Select(Mapper.Map<TDto>).AsTask();
// or you can use Mapper.Map to a list of entities.
dtos = await Mapper.Map<List<TDto>>(entities).AsTask();
return dtos;
}
catch(Exception ex)
{
// side note, don't throw ex, you'll lose the stack trace
throw;
}
}
我只在使用 ProjectTo 时收到错误,我无法理解根本问题。 (Automapper 版本我使用的是 4.2.1.0) “LINQ to Entities 不支持指定的类型成员 'Tags'。 仅支持初始值设定项、实体成员和实体导航属性。" 我们也可以在 DTO 中进行这种操作,但我应该坚持只在实体方面进行操作。 请让我知道在不升级版本的情况下我可以处理这个问题的方法或解决方法。 TIA 我希望实体的 Tags 属性 的计算值需要映射到 DTO 的 Tags 属性,但是当我以正常方式进行时这工作正常。
Source/destination 类型
public class Template : IEntity<int>
{
public string Name { get; set; }
public int Id { get; set; }
public string _Tags { get; set; }
[NotMapped]
public List<string> Tags
{
get { return _Tags == null ? null : JsonConvert.DeserializeObject<List<string>>(_Tags); }
set { _Tags = JsonConvert.SerializeObject(value); }
}
}
实体配置
internal sealed class TemplateConfig : EntityTypeConfiguration<Template>
{
public TemplateConfig()
{
Ignore(x => x.Tags);
HasKey(x => x.Id)
.Map(m =>
{
m.ToTable("Template");
m.Property(x => x.Id).HasColumnName("ID");
m.Property(x => x.Name).HasColumnName("Name");
m.Property(x => x._Tags).HasColumnName("Tags");
});
}
}
目标 DTO:
public class Template
{
public int Id { get; set; }
public string Name { get; set; }
public List<string> Tags { get; set; }
}
映射配置
Mapper.CreateMap<Template, DTO.Template>();
Mapper.CreateMap<DTO.Template, Template>();
//These are just for information, but getting error only when using ProjectTo. (Ignore about the OData thing)
public virtual async Task<IQueryable<TDto>> Get(ODataQueryOptions<TDto> query)
{
try
{
var expands = query.GetExpandedPropertyNames();
//Assume the collection has the data from db
var test = Collection.ToList();
//getting the exception here
return await Collection.ProjectTo<TDto>(null, expands).AsTask();
}
catch(Exception ex)
{
throw ex;
}
}
//Controller method
public override async Task<IQueryable<Template>> Get(ODataQueryOptions<Template> query)
{
try
{
List<Template> result = (await base.Get(query)).ToList();
return result.AsEnumerable().AsQueryable();
}
catch(Exception ex)
{
throw ex;
}
}
您是否尝试过在 MappingConfiguration 中实现忽略?我不太清楚你在哪个方向上遇到问题,但类似于:
Mapper.CreateMap<Template, DTO.Template>()
.ForMember(dest => dest.Tags, opts => opts.Ignore());
发生这种情况是因为 .ProjectTo<>(...)
正在 SQL 中为您构建 select 语句。由于 .Tags
在您的对象之间映射,它被包含在 select 语句中,然后 entity framework 抱怨它不能这样做(因为 NotMapped
属性).
而不是使用 ProjectTo<>(...)
你可以只使用普通的 .ToList()
然后使用 .Select(Mapper.Map<TDto>)
或 Mapper.Map<List<TDto>>(list)
.
这应该可行,因为 entity framework 将从字符串字段填充您的标签字段,automapper 可以正常进行映射。
public virtual async Task<IQueryable<TDto>> Get(ODataQueryOptions<TDto> query)
{
try
{
var expands = query.GetExpandedPropertyNames();
//Assume the collection has the data from db
var test = Collection.ToList();
var entities = expands.ToList();
// you can either use .Select to project using LINQ
var dtos = await entities.Select(Mapper.Map<TDto>).AsTask();
// or you can use Mapper.Map to a list of entities.
dtos = await Mapper.Map<List<TDto>>(entities).AsTask();
return dtos;
}
catch(Exception ex)
{
// side note, don't throw ex, you'll lose the stack trace
throw;
}
}