I'm trying to use the ProjectUsing feature of AutoMapper to only select the columns I need through a LINQ expression but it seems the expression itself does not get called at run-time or via unit testing.
As a test I am just putting a fixed value into the AlternateId property but the assert below always fails. This also fails with single instances (not in a queryable list) and at run-time via Entity Framework 6.
class MapFrom
{
public int Id { get; set; }
}
class MapTo
{
public int AlternateId { get; set; }
}
[TestMethod]
public void Automapper_projectusing_test()
{
AutoMapper
.Mapper
.CreateMap<MapFrom, MapTo>()
.ProjectUsing(src => new MapTo { AlternateId = 88 });
var products = new List<MapFrom>();
products.Add(new MapFrom());
var mapped = products
.AsQueryable() // Just in case ProjectUsing only works with IQueryable.
.Project()
.To<MapTo>()
.ToList();
Assert.AreEqual(88, mapped.Single().AlternateId); // Fails, AlternateId equals 0.
}
Using AutoMapper v3.3.1, NCrunch confirms that the mapping expression code is never executed.
Why is AutoMapper not executing this expression, perhaps I'm missing a key step?
According to Jimmy Bogarde 'This works as designed, you want ConstructUsing.'. See
https://github.com/AutoMapper/AutoMapper/issues/677#event-289561571
Obviously it's caught us all out so I think the documentation could be clearer here.
I was trying to do the same thing and came across this issue and could not figure it out either. I downloaded the Automapper source and had a look at the associated tests.
public ProjectEnumTest()
{
Mapper.CreateMap<Customer, CustomerDto>();
Mapper.CreateMap<CustomerType, string>().ProjectUsing(ct => ct.ToString().ToUpper());
}
[Fact]
public void ProjectingEnumToString()
{
var customers = new[] { new Customer() { FirstName = "Bill", LastName = "White", CustomerType = CustomerType.Vip } }.AsQueryable();
var projected = customers.Project().To<CustomerDto>();
projected.ShouldNotBeNull();
Assert.Equal(customers.Single().CustomerType.ToString().ToUpper(), projected.Single().CustomerType);
}
The short answer is this only appears to work on member level mappings and not first class level mappings? Substituting the mapping with below does not work. The projected value is just a CustomerDto object with null properties.
Mapper.CreateMap<Customer, CustomerDto>().ProjectUsing(c => new CustomerDto{FirstName = "Test"});
From the article listed here: http://lostechies.com/jimmybogard/2014/12/23/automapper-3-3-feature-projection-conversions/ I would assume the above functionality might be intended, but does not work. Either that, or there is a configuration problem with both our understanding of how this works.
Related
I am trying to set up property for an entity which uses entity's objects (other entities loaded from database based on foreign key). My code looks like this:
[Table("Notes")]
public class Note : FullAuditedEntity
{
public virtual int EntityAId { get; set; }
public EntityA EntityA { get; set; }
public virtual int EntityBId { get; set; }
public EntityB EntityB { get; set; }
public List<NoteXHashtag> AdditionalHashtags { get; set; } = new List<CardXHashtag>();
[NotMapped]
public List<Hashtag> AllHashtags
{
get
{
List<Hashtag> allHashtags = new List<Hashtag>();
allHashtags.AddRange(AdditionalHashtags.Select(x => x.Hashtag));
allHashtags.Add(EntityA.Hashtag);
allHashtags.Add(EntityB.Hashtag);
return allHashtags;
}
}
}
When I try to use property AllHashtags from outside, EntityA and EntityB are null. How to tell Entity Framework to load them from database when I need to work with them?
Note: When I am calling AllHashtags from outside, I have both EntityA and EntityB Included:
noteRepository
.GetAll()
.Include(x => x.AdditionalHashtags).ThenInclude(x => x.Hashtag)
.Include(x => x.EntityA).ThenInclude(x => x.Hashtag)
.Include(x => x.EntityB).ThenInclude(x => x.Hashtag)
.Select(x => new NoteDetailDto()
{
Id = x.Id,
AllHashtags = x.AllHashtags
});
If you are using projection (.Select()) then you do not need to use .Include() to have access to related entities.
I would start by looking at what your repository .GetAll() method is returning. .Include() only works against IQueryable so if the repository method is effectively doing something like this:
return _context.Notes.AsQueryable();
or this:
return _context.Notes.Where(x => x.SomeCondition);
Then you can leverage Include() outside of the repository method. However, if you were returning something like this:
return _context.Notes.Where(x => x.SomeCondition).ToList().AsQueryable();
Then the type would grant access the Include() method, but Include would not actually include the related tables. You can observe this by using a profiler on the database to inspect the queries. With Include, the query would join the EntityA and EntityB tables into the SELECT statement.
With regards to your example statement, it's obviously a simplified example you've supplied, but from what I can see it should not execute if the GetAll() method was returning an EF IQueryable. If it did return an EF IQueryable then accessing the AllHashtags property in a Select would result in an error because AllHashtags is not a mapped property of Note. This means that if your real code looks something like that, then GetAll() is not returning an EF IQueryable, or you've possibly created extension methods for Include/ThenInclude for IEnumerable that do an AsQueryable() to satisfy the EF include operations. (These will not work)
To get the results you want, I would recommend avoiding the use of an unmapped property on the entity, but rather take a 2-step approach with an anonymous type and keep the business logic transformation in the business layer:
Step 1. Ensure that the repository method is just returning an EF IQueryable, so context.[DbSet<TEntity>].AsQueryable() or context.[DbSet<TEntity>].Where([condition]) is fine:
return _context.Notes.AsQueryable();
Step 2. Define a DTO for your Hashtag. (avoid send/receive entities)
[Serializable]
public class HashtagDto
{
public int Id { get; set;}
public string Text { get; set; }
// etc.
}
Step 3. Select the appropriate fields you care about into an anonymous type and materialize it:
var noteData = repository.GetAll()
.Select( x= > new {
x.Id,
AdditionalHashtags = x.AdditionalHashtags.Select(h => new HashtagDto { Id = h.Id, Text = h.Text }).ToList(),
EntityAHashtag = new HashTagDto { Id = x.EntityA.Hashtag.Id, Text = x.EntityA.Hashtag.Text },
EntityBHashtag = new HashTagDto { Id = x.EntityB.Hashtag.Id, Text = x.EntityB.Hashtag.Text },
).ToList();
Step 4. Compose your view model / DTO:
var noteDetails = noteData.Select(x => new NoteDetailDto
{
Id = x.Id,
AllHashTags = condenseHashtags(x.AdditionalHashtags, EntityAHashtag, EntityBHashtag);
}).ToList();
Where the condenseHashtags is just a simple utility method:
private static ICollection<HashTagDto> condenseHashtags(IEnumerable<HashtagDto> source1, HashtagDto source2, HashtagDto source3)
{
var condensedHashtags = new List<HashtagDto>(source1);
if (source2 != null)
condensedHashtags.Add(source2);
if (source3 != null)
condensedHashtags.Add(source3);
return condensedHashtags;
}
The above example is synchronous, it can be transformed into async code without too much trouble if load performance is a concern for server responsiveness.
Steps 3 & 4 can be combined in a single statement, but there needs to be a .ToList() between them as Step 4 needs to run against Linq2Object to condense the hashtags. Step 3 ensures that the Linq2EF expression composes an efficient query to just return the information about the Note, and the associated hashtags that we care about, nothing more. Step 4 condenses those individual details into a DTO structure we intend to return.
Step 2 is important as you should avoid sending Entities back to the client/consumers. Sending entities can lead to performance issues and possible errors if lazy loading is enabled, or leads to incomplete renditions of data being passed around if lazy loading isn't enabled and you neglect to eager-load related info. (Is a related detail really #null, or did you forget to include it?) It can also reveal more about your data structure than consumers should necessarily know, and reflects larger data transfer packets than are needed. Accepting entities back from a client is highly inadvisable since it opens the door for unexpected data tampering, stale data overwrites, and your typical gambit of bugs around dealing with reattaching detached entities that a context may know about. If your code simply attaches entities to a DbContext, sets the modified state, and saves changes. Even if you don't do that today, it opens the door for later modifications to start doing it given an entity is already present in the call. Receive DTOs, load the entity, validate a row version, validate the snot out of the DTO against the entity, and only update the fields that are expected to change.
I am trying to automap two lists with automapper, based on a Handle property. Similarly to an inner join. Is this possible with automapper 9.0.0.0?
public class MyObject
{
public int Handle { get; set; }
public string Name { get; set; }
}
public class MyObjectExtension
{
public int Handle { get; set; }
public string Description{ get; set; }
}
public class MyRichObject
{
public int Handle { get; set; }
public string Name { get; set; }
public string Description{ get; set; }
}
//and here my mapper usage:
IEnumerable<MyObject> MyObjects;
IEnumerable<MyObjectExtension> MyObjectExtensions;
IEnumerable<MyRichObject> MyRichObjects;
// mapping to a new object
MyRichObjects= Mapper.Map<IEnumerable<MyRichObject>(MyObjects);
// adding MyObjectExtension properties by mapping to the existing RichObject
MyRichObjects= Mapper.Map<IEnumerable<MyObjectExtension>, IEnumerable<MyRichObject>>(MyObjectExtensions, MyRichObjects);
This last lige of code works, but it probably maps the elements in the two lists one by one and I would like to map them based on the Handle property.
Here is how I add the Automapper bindings for NInject in my NInjectDependencyResolver class, but how do I set up cfg.AddCollectionMappers()??;
// AutoMapper mapping
kernel.Bind<MapperConfiguration>()
.ToSelf()
.WithConstructorArgument<Action<IMapperConfigurationExpression>>(
cfg => new Mappers.AutoMapperConfiguration(cfg));
//.InRequestScope()
kernel.Bind<IConfigurationProvider>().ToMethod(ctx => ctx.Kernel.Get<MapperConfiguration>());
kernel.Bind<IMapper>().ToMethod(maper => kernel.Get<MapperConfiguration>().CreateMapper()).InSingletonScope();
kernel.Bind<IExpressionBuilder>().ToConstructor(ctx => new ExpressionBuilder(kernel.Get<MapperConfiguration>()));
AutoMapper 9 removed static mappings so the question's code can only work if Mapper is a an IMapper property or field holding a reference to a mapper instance.
As the AutoMapper docs say :
When mapping to an existing collection, the destination collection is cleared first. If this is not what you want, take a look at AutoMapper.Collection.
The library's Github page shows that matching by handle requires adding Collections to the mapper configuration and specifying the object equivalence with a single line :
cfg.AddCollectionMappers();
...
cfg.CreateMap<MyObjectExtension, MyRichObject>()
.EqualityComparison( (oe, ro) => oe.Handle == ro.Handle);
After that, you can just call Map without any modifications :
mapper.Map(MyObjectExtensions, MyRichObjects);
This is quite similar to a LINQ Join. In fact, the mapping implementation is quite similar to Enumerable.Join's implementation - both methods create a Lookup table of the destination to speed up lookups before iterating over the source. AutoMapper goes one step further though and updates the destination objects with the matching source properties.
Notice that destination has to be an ICollection<T>. It can't be an IEnumerable<T> because that interface doesn't allow modifications.
An alternative to this would be to use a LINQ join between MyObjects and MyObjectExtensions:
var richObjects=myObjects.Join(myObjectsExtensions,
o => o.Handle,
oe => oe.Handle,
(o,oe)=>new MyRichObject {
Handle = o.Handle,
Name = o.Name,
Description = oe.Description
})
.ToArray();
Important
All this would make sense if the data is already in memory. For data stored in a database it's far faster and cheaper (and easier) to execute a SQL statement with a JOIN that will return the final object directly. That query can be generated by an ORM like EF (Core) or executed directly by a micro-ORM like Dapper.
I think that,in your case, is better use Linq.
For Instance:
List<MyObject> listMyObject = new List<MyObject>();
listMyObject.Add(new MyObject() { Handle = 1, Name = "FirstName" });
listMyObject.Add(new MyObject() { Handle = 2, Name = "SecondName" });
listMyObject.Add(new MyObject() { Handle = 3, Name = "ThirdName" });
List<MyObjectExtension> listMyObjectExtensions = new List<MyObjectExtension>();
listMyObjectExtensions.Add(new MyObjectExtension() { Handle = 1, Description = "FirstDescription" });
listMyObjectExtensions.Add(new MyObjectExtension() { Handle = 2, Description = "SecondDescription" });
listMyObjectExtensions.Add(new MyObjectExtension() { Handle = 3, Description = "ThirdDescription" });
IEnumerable<MyObject> MyObjects = listMyObject.AsEnumerable<MyObject>();
IEnumerable<MyObjectExtension> MyObjectExtensions = listMyObjectExtensions.AsEnumerable<MyObjectExtension>();
IEnumerable<MyRichObject> MyRichObjects;
MyRichObjects = from myObject in MyObjects
join myObjectExtension in MyObjectExtensions on myObject.Handle equals myObjectExtension.Handle
select new MyRichObject { Handle = myObject.Handle, Name = myObject.Name, Description = myObjectExtension.Description };
foreach (var MyRichObject in MyRichObjects)
{
System.Diagnostics.Debug.WriteLine($"Id: \"{MyRichObject.Handle}\". Name: {MyRichObject.Name} Description: {MyRichObject.Description}");
}
Return:
Id: "1". Name: FirstName Description: FirstDescription
Id: "2". Name: SecondName Description: SecondDescription
Id: "3". Name: ThirdName Description: ThirdDescription
I am trying to work out how to use the .NET EntityFramework to generate both readable and natural code and efficient SQL query statements when fetching related entities. For example, given the following code-first definition
public class WidgetContext : DbContext
{
public DbSet<Widget> Widgets { get; set; }
public DbSet<Gizmo> Gizmos { get; set; }
}
public class Widget
{
public virtual int Id { get; set; }
[Index]
[MaxLength(512)]
public virtual string Name { get; set; }
public virtual ICollection<Gizmo> Gizmos { get; set; }
}
public class Gizmo
{
public virtual long Id { get; set; }
[Index]
[MaxLength(512)]
public virtual string Name { get; set; }
public virtual Widget Widget { get; set; }
public virtual int WidgetId { get; set; }
}
I want to be able to write code like
using (var wc = new WidgetContext())
{
var widget = wc.Widgets.First(x => x.Id == 123);
var gizmo = widget.Gizmos.First(x => x.Name == "gizmo 99");
}
and see a SQL query created along the lines of
SELECT TOP (1) * from Gizmos WHERE WidgetId = 123 AND Name = 'gizmo 99'
So that the work of picking the right Gizmo is performed by the database. This is important because in my use case each Widget could have thousands of related Gizmos and in a particular request I only need to retrieve one at a time. Unfortunately the code above causes the EntityFramework to create SQL like this instead
SELECT * from Gizmos WHERE WidgetId = 123
The match on Gizmo.Name is then being performed in memory by scanning the complete set of related Gizmo entities.
After a good deal of experimentation, I have found ways of creating the efficient SQL use I am looking for in the entity framework, but only by using ugly code which is much less natural to write. The example below illustrates this.
using System.Data.Entity;
using System.Data.Entity.Core.Objects.DataClasses;
using System.Linq;
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<WidgetContext>());
using (var wc = new WidgetContext())
{
var widget = new Widget() { Name = "my widget"};
wc.Widgets.Add(widget);
wc.SaveChanges();
}
using (var wc = new WidgetContext())
{
var widget = wc.Widgets.First();
for (int i = 0; i < 1000; i++)
widget.Gizmos.Add(new Gizmo() { Name = string.Format("gizmo {0}", i) });
wc.SaveChanges();
}
using (var wc = new WidgetContext())
{
wc.Database.Log = Console.WriteLine;
var widget = wc.Widgets.First();
Console.WriteLine("=====> Query 1");
// queries all gizmos associated with the widget and then runs the 'First' query in memory. Nice code, ugly database usage
var g1 = widget.Gizmos.First(x => x.Name == "gizmo 99");
Console.WriteLine("=====> Query 2");
// queries on the DB with two terms in the WHERE clause - only pulls one record, good SQL, ugly code
var g2 = ((EntityCollection<Gizmo>) widget.Gizmos).CreateSourceQuery().First(x => x.Name == "gizmo 99");
Console.WriteLine("=====> Query 3");
// queries on the DB with two terms in the WHERE clause - only pulls one record, good SQL, ugly code
var g3 = wc.Gizmos.First(x => x.Name == "gizmo 99" && x.WidgetId == widget.Id);
Console.WriteLine("=====> Query 4");
// queries on the DB with two terms in the WHERE clause - only pulls one record, also good SQL, ugly code
var g4 = wc.Entry(widget).Collection(x => x.Gizmos).Query().First(x => x.Name == "gizmo 99");
}
Console.ReadLine();
}
Query 1 demonstrates the 'fetch everything and filter' approach that is generated by the natural usage of the entity objects.
Queries 2,3 and 4 above all generate what I would consider to be an efficient SQL query - one that returns a single row and has two terms in the WHERE clause, but they all involve very stilted C# code.
Does anyone have a solution that will allow natural C# code to be written and generate efficient SQL utilization in this case?
I should note that I have tried replacing ICollection with EntityCollection in my Widget object to allow the cast to be removed from the Query 2 code above. Unfortunately this leads to an EntityException telling me that
The object could not be added to the EntityCollection or
EntityReference. An object that is attached to an ObjectContext cannot
be added to an EntityCollection or EntityReference that is not
associated with a source object.
when I try to retrieve any related objects.
Any suggestions appreciated.
Ok, further digging has let me get as close as I think is possible to where I want to be (which, to reiterate, is code that looks OO but generates efficient DB usage patterns).
It turns out that Query2 above (casting the related collection to an EntityCollection) actually isn't a good solution, since although it generates the desired query type against the database, the mere act of fetching the Gizmos collection from the widget is enough to make the entity framework go off to the database and fetch all related Gizmos - i.e. performing the query that I am trying to avoid.
However, it's possible to get the EntityCollection for a relationship without calling the getter of the collection property, as described here http://blogs.msdn.com/b/alexj/archive/2009/06/08/tip-24-how-to-get-the-objectcontext-from-an-entity.aspx. This approach sidesteps the entity framework fetching related entities when you access the Gizmos collection property.
So, an additional read-only property on the Widget can be added like this
public IQueryable<Gizmo> GizmosQuery
{
get
{
var relationshipManager = ((IEntityWithRelationships)this).RelationshipManager;
return (IQueryable<Gizmo>) relationshipManager.GetAllRelatedEnds().First( x => x is EntityCollection<Gizmo>).CreateSourceQuery();
}
}
and then the calling code can look like this
var g1 = widget.GizmosQuery.First(x => x.Name == "gizmo 99");
This approach generates SQL that efficiently fetches only a single row from the database, but depends on the following conditions holding true
Only one relationship from the source to the target type. Having multiple relationships linking a Widget to Gizmos would mean a more complicated predicate would be needed in the .First() call in GizmosQuery.
Proxy creation is enabled for the DbContext and the Widget class is eligible for proxy generation (https://msdn.microsoft.com/en-us/library/vstudio/dd468057%28v=vs.100%29.aspx)
The GizmosQuery property must not be called on objects that are newly created using new Widget() since these will not be proxies and will not implement IEntityWithRelationships. New objects that are valid proxies can be created using wc.Widgets.Create() instead if necessary.
I am using Entity Framework and Breeze. For an Entity, there is a bit of associated data I would like to provide with the entity. Getting this data is most efficiently done by querying the Entity table and joining to other tables; this query includes a group by sub-query.
I am attempting to tack this extra data on by adding it as a [NotMapped] field to the entity:
[NotMapped]
public string NotMappedField { get; set; }
So then I basically want to replace this webapi controller method
[HttpGet]
public IQueryable<MyObject> MyObjects()
{
return _contextProvider.Context.MyObjects;
}
With something like this:
public IQueryable<MyObject> MyObjectsWithExtraData()
{
var query = from o in _contextProvider.Context.MyObjects
// big complex query
select new MyObject
{
FieldA = o.FieldA,
FieldB = o.FieldB,
// all fields
NotMappedField = x.ResultFromComplexJoin
}
return query;
}
This gives me an error:
The entity or complex type 'MyObject' cannot be constructed in a LINQ to Entities query.
I've tried this a few ways and it seems to fight me both from the EF side and the Breeze side. I need to keep this as returning something like IQueryable so I can filter from the client through webapi because doing something like a ToList() here causes memory issues due to the dataset size.
So my question is - is there a best practices kind of way to accomplish what I am attempting or can anyone provide a solution?
Update:
I have found you can return extra data alongside of your entity and still have access to the entity as a queryable from Breeze:
public object MyObjectsWithExtraData()
{
var query = from o in _contextProvider.Context.MyObjects
// big complex query....
select new
{
theObject = MyObject,
NotMappedField = x.ResultFromComplexJoin
};
return query;
}
and then from the client breeze side you can do something like this:
var query = breeze.EntityQuery
.from("MyObjectsWithExtraData")
.where("theObject.FieldA", "Equals", 1)
.expand("theObject.SomeNavigationalProperty")
.orderBy("theObject.FieldB");
Still not exactly what I was looking for but it is actually pretty slick.
Take a look at the EntityQuery.withParameters method.
// client side
var q = EntityQuery.from("CustomersStartingWith")
.withParameters({ companyName: "C" });
// server side
[HttpGet]
public IQueryable<Customer> CustomersStartingWith(string companyName) {
var custs = ContextProvider.Context.Customers.Where(c => c.CompanyName.StartsWith(companyName));
return custs;
}
You can also mix and match a combination of regular query predicates with these custom parameters.
LINQ to entity can only construct pur "Data Transfert Object" : class containing only public properties with trivial getter and setter and without constructor.
See my answer to a similar question here : https://stackoverflow.com/a/21174654/3187237
I specify my answer
An Entity class can't be instanciated in a LINQ to Entities query.
If you want to construct similar (or almost similar) in the query you have to define an other class.
In your case you want to return object almost similar to your MyObject. So you have to define a class:
public class MyObjectExtended
{
public string FieldA { get; set; }
public string FieldB { get; set; }
// ... all other MyObjetc fields
public string ExtraFieldA { get; set; }
public string ExtraFieldB { get; set; }
}
Now, your service can return a IQueryable<MyObjectExtended>:
public IQueryable<MyObjectExtended> MyObjectsWithExtraData() {
var myQuery = from o in _contextProvider.Context.MyObjects
// big complex query....
select new MyObjectExtended {
FieldA = o.FieldA,
FieldB = o.FieldB,
//... all fields ...
ExtraFieldA = x.ResultFromComplexJoinA,
ExtraFieldB = x.ResultFromComplexJoinB
};
return myQuery;
}
I hope this is what you are looking for.
I have a simple mapping and it is working but it's not filling in Output.Details.
I am a bit confused, I think it maybe because I am using the source as "Task" for each one.
Mapper.CreateMap<Task, Output>();
Mapper.CreateMap<Task, Output.Details>().ForMember(
dest => dest.Item, opt => opt.MapFrom(src => src.Name));
As far as i know i have to create 2 maps, 1 for the object and 1 for object contained within.
Problem is the source for the OUTPUT and OUTPUT.DETAILS can be found in TASK
I tried delving into Details within the first map and specifying Mapfrom but it gives the following error which is why i must create 2 maps
must resolve to top-level member. Parameter name: lambdaExpression error
IList<Task> tempItems= GetItems();
IList<Output> items =
Mapper.Map<IList<Task>, IList<Output>>(tempItems);
The map works but my property "Item" availble in Output.Details is NULL
What am I doing wrong? Here is my Destination object.
It fills in Name no problem, but nothing inside DETAILS... they are left NULL.
Task is not my class, but I checked it and all values are there to be copied hence Tag has a value and is a STRING.
public class Output
{
public string Name { get; set; }
public Details Summary { get; private set; }
public class Details
{
public string Item{ get; set; }
}
public Output()
{
Summary = new Details();
}
}
EDIT
Here is an example of the Task class.
EDIT
They is a sample vs 2010 project here and it shows exactly the problem.
http://dl.dropbox.com/u/20103903/AutomapperNotWorking.zip
and here is an image showing the issue, as you can see Summary Item is "NULL" but it should contain the NAME from Task.
First off, always use Mapper.AssertConfigurationIsValid(); to make sure your mapping configuration is valid. I added it to your code and it immediately highlighted the problem: You didn't tell Automapper what to do with the Summary property. Since Task doesn't contain a property called Summary, Automapper needs to know what to do with it.
So the problem isn't really how to map a nested class, you just need to tell Automapper what to do with Summary. Here's the Automapper configuration that works for your example:
Mapper.CreateMap<Task, Output>()
.ForMember(d => d.Summary, o => o.MapFrom(t => new Output.Details {Item = t.Name}));
Mapper.AssertConfigurationIsValid();
That's all you need.
for the new version, it can be performed as follow:
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<UdtDevQuestion, QuestionViewModel>();
});
config.AssertConfigurationIsValid();