0

I have a business need to dynamically select ONLY the properties of a given model that are specified, similar to an OData select clause. I am currently using Mapster's ProjectToType functionality to populate view models from EF Core entities.

Is there any way to tell Mapster to only select a given list of properties in the query that it generates? Or a way to take the full model mapping, and change mappings at runtime in an instance of TypeAdapterConfig to ignore properties that aren't in a given list of properties?

The end solution needs to be generic and work with navigation properties, because it will be applied to all of our entities in the database. We also used DynamicLinq in some cases, not sure if that can be used on top of Mapsters ProjectToType functionality.

Example:

Entities (Some properties omitted for length):

namespace DataAccess.Entities
{
    public class Series
    {
        public Guid Id { get; set; }
        public string Description { get; set; }
        public long? StackRank { get; set; }
        public string EntityId { get; set; }
        // Other properties
    }

    public class Model
    {
        public Guid Id { get; set; }
        public string Description { get; set; }
        public string EntityId { get; set; }
        public long? StackRank { get; set; }
        public Guid SeriesId { get; set; }
        
        public virtual Series Series { get; set; }
        
        // Other properties

    }
}

View Models (Some properties omitted for length):

namespace Models
{
    public class Model
    {
        public Guid Id { get; set; }
        public string Description { get; set; }
        public string EntityId { get; set; }
        public long? StackRank { get; set; }
        public Guid SeriesId { get; set; }
        
        public virtual Series Series { get; set; }
        
        // Other properties
    }
    
    public class Series
    {
        public Guid Id { get; set; }
        public string Description { get; set; }
        public long? StackRank { get; set; }
        public string EntityId { get; set; }
        // Other properties
    }
}

Given a rest call to get a list of all Model view models, with this list of properties to include:

var properties = new List<string> {
"Id",
"EntityId"
"Description",
"Series.Id",
"Series.Description",
"Series.EntityId"
}

The results would return some type of dictionary, dynamic, or anonymous object that contained ONLY these properties, and the other properties would not even be included in the final select of the SQL query that gets created.

Michael Rentmeister
  • 167
  • 1
  • 6
  • 24
  • I can do that without Mapster. I think it is not needed in this case. – Svyatoslav Danyliv Jun 01 '21 at 17:49
  • 1
    You can probably generate the mapper on the fly and use conditional ignore configuration: https://github.com/MapsterMapper/Mapster/wiki/Ignoring-members#ignore-conditionally – Arca Artem Jun 01 '21 at 20:37
  • I think it's at odds with OData (i.e. REST) principles to return partially populated entities. Just one major objection, what do you do when such entities are PUT back? Either follow the protocol or don't use OData. Returning dictionaries is even a further departure from REST. I don't understand why you don't want to return intact entities. – Gert Arnold Jun 04 '21 at 12:45
  • @GertArnold - our business use case is that our users can customize our grids to see whatever columns they would like, and we don't have to have to pull the data for all columns if we don't have to. For example, some of our database tables have 50 columns, but the user only cares about 5. Also, we use PATCH instead of PUT – Michael Rentmeister Jun 18 '21 at 15:09

1 Answers1

0

In the end, I decided to use Arca Artem's suggestion, with a little twist. I used reflection to grab a list of all properties of the model and cache them. After that, I compared the cached properties vs the list of properties to include, and ignored the properties that weren't in both lists. Kinda like this:

var clonedConfig = mapsterInstance.Clone();
clonedConfig.ForType<TSource, TDestination>().Ignore(propertiesToIgnore);
var models = await query.ProjectToType<TDestination>(clonedConfig).ToListAsync();

Maybe not the most elegant solution, but it worked well enough for what I needed. I also set up our json serializer to ignore null values.

Michael Rentmeister
  • 167
  • 1
  • 6
  • 24