在源中使用NotMapped / Computed属性在目标中映射时自动执行ProjectTo<>()问题

时间:2017-05-03 18:15:18

标签: c# entity-framework entity-framework-6 linq-to-entities automapper

我只是在使用ProjectTo时才收到错误,我无法理解底层问题。 (Automapper版本使用4.2.1.0)     “LINQ to Entities中不支持指定的类型成员'标签'。             仅支持初始化程序,实体成员和实体导航属性。“     我们也可以在DTO中进行这种操作,但我应该坚持只在实体方面进行操作。 请告诉我解决方法或解决方法,我可以在不升级版本的情况下处理此问题。 TIA 我希望实体的Tags属性的计算值需要映射到DTO的Tags属性,但是当我按照正常方式工作时这很好。

来源/目的地类型

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;
                }
            }

2 个答案:

答案 0 :(得分:1)

这种情况正在发生,因为.ProjectTo<>(...)正在SQL中为您构建select语句。由于.Tags在您的对象之间映射,它被包含在select语句中,然后实体框架抱怨它不能这样做(因为NotMapped属性)。

您可以使用普通ProjectTo<>(...),然后使用.ToList().Select(Mapper.Map<TDto>),而不是使用Mapper.Map<List<TDto>>(list)

这应该有效,因为实体框架会从字符串字段填充你的Tags字段,而者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;
    }
}

答案 1 :(得分:0)

您是否尝试在MappingConfiguration中实现ignore?我无法确定你遇到问题的方向,但是有点像:

Mapper.CreateMap<Template, DTO.Template>()
    .ForMember(dest => dest.Tags, opts => opts.Ignore());