public class ProfileA : ProfileB
{
CreateMap<Source, Destination>(d => d.Age, opt => opt.UseValue(14));
}
public class ProfileB : Profile
{
public ProfileB()
{
CreateMap<Source, Destination>(d => d.Name, opt => opt.UseValue("qqq"));
}
}
Even though the maps are on same source and destination type I want the separation by creating a base Profile then inheriting and creating more specific Profiles. But as with above code only ProfileA's mappers will be applied.
How can I achieve such feat using AutoMapper or is it even considered a good practice for AutoMapper?
Having the same map in different profiles is an anti-pattern and is not allowed by default. There is only one map and overriding it in this way only makes things difficult. See this. It can be overridden.
Related
Is there a way to dynamically generate multiple maps? For example, can I map to an array of source and destination values? I am working with a legacy database and one of the tables has over 350+ columns. It will be very error prone and labor intensive to map each field manually.
//HOW CAN BELOW INCLUDE OVER 350+ MAPPED FIELDS DYNAMICALLY FROM AN ARRAY?
CreateMap<Employee, EditEmployeeModel>()
.ForMember(dest => dest.ConfirmEmail,
opt => opt.MapFrom(src => src.Email));
Basically if the property names are similar then you don't have to map source to destination manually. Automapper will do this automatically. So, if you keep the property names similar then there's no need to map.
But if that's not possible and keeping different names is a necessity then you can use .AfterMap() feature of Automapper. It is simpler than source destination mapping.
public class EditEmployeeMap : IMappingAction<Employee, EditEmployeeModel>
{
public void Process(Employee source, EditEmployeeModel destination, ResolutionContext context)
{
destination.ConfirmEmail = source.Email;
}
}
Then,
CreateMap<Employee, EditEmployeeModel>().AfterMap<EditEmployeeMap>();
Though the purpose of the above solution is not for this use case, this can make the job more simple for you.
But i would suggest to keep the property name similar, that will save a lot of hastle.
I'm working on a project and I need to map collections. I came across Automapper.Collection and am trying to user the class but its all not working. Please I need help. Here is my code.
In my startup class
services.AddAutoMapper(cfg => { cfg.AddCollectionMappers(); },typeof(Startup));
I also created a class that Inherits from the Automapper Profile class here
public class UserMappingProfile : Profile
{
public UserMappingProfile()
{
CreateMap<PhotoToUpdateDto, Photo>().EqualityComparison((src, dest) => src.PublicId.ToLower() == dest.PublicId.ToLower());
CreateMap<SocialHandles, SocialHandleDto>().ReverseMap().EqualityComparison((src, dest) => src.Name.ToLower() == dest.Name.ToLower());
}
}
Anytime I use the mapper, it creates new records in the database instead of updating the already existing. Please I need help.
I think its because of navigation property in your entity
If you have navigation property ignore them in your Createmap
For example
CreateMap<PhotoToUpdateDto, Photo>().EqualityComparison((src, dest) =>
src.PublicId.ToLower() == dest.PublicId.ToLower())
.ForMember(p => p.Photographer , opt => opt.Ignore());
I'll assume this:
You have no problem with the mapper (since it still map your object successfully).
When you get new object to interact with database, a new record created, since your make sure the id mapping was correct.
You are using EF Core or some kind of ORM to interact with the database
If i was wrong, please just ignore this answer.
Okay, If my assuming was right, that's because automapper always return a new object as result of the mapping process, which is absolutely not tracked by your DbContext yet. And then, whenever you interact with that to make some change in the database, an add operation is likely going to happen.
I think you need to add some more information about the block of code that you actually have problem with... which in this case... why the database entry keep created, but not update.
How many ways are there to map a database with Entity Framework in .NET?
I understand there is code-first and database-first (using .EDMX wizard for example).
Within the context of database-first, can I map my tables and relationships manually without using .EDMX? How many ways exist and which do you recommend?
Are there libraries for manual table mapping, which are the best?
I think there is not a best way, but maybe there is a way that fits best your needs.
I'll try to explain the ways you have, than you can choose the best for you.
On high level, there are two options:
DB first: you define the database and let a tool to create your model classes
Code first: you define your classes and let EF manage the tables for you
Mainly DB first is the best for:
Map an already existing database: in this situation your DB is already designed, so you have only to map entities
Your focus is the DB structure: in this situation, better if you design your DB as you want, then let a tool to map your entities
Code first is the best when you don't mind about the DB but you want to think about the object model. Of course, you can change how the DB is generated using data annotation or any other way EF gives you, but the focus for you has to be the object model.
Hi yes can can absolutely Map a database from EF. It is called scaffolding. What it does is it creates the database as models and required files for you.
Once you open the package manage or cmd you can type the following one-liner to scafford you database:
CMD:
dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer
Package Manager:
Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer
See the EF Core tutorial on it on the official windows website:
https://learn.microsoft.com/en-us/ef/core/managing-schemas/scaffolding?tabs=dotnet-core-cli
And for EF6 there is a great tutorial right here:
https://www.illucit.com/en/asp-net/entity-framework-7-code-first-migrations/
For full manual control with a Database-First project you can leverage a combination of convention, attributes, and/or entity configurations to configure the entities. Scaffolding I find works 90% of the time, but usually there will be some aspect of a production schema, especially where you don't have the flexibility to change the schema to make it more ORM-friendly, that scaffolding doesn't quite handle.
Also, if you're adopting something like bounded contexts (think DbContexts with fit-for-purpose mappings) and want to customize how tables/views map to entities, then it helps to be more explicit with the mapping. For example, for general entities I will map navigation properties, but in cases where I want raw performance over larger operations I will want to forgo declaring navigation properties and work strictly with FK columns. The less "mapping" a DbContext has to worry about and fewer entities it is tracking, the faster it performs.
Attributes: Here you declare your entity classes and use the appropriate attributes to describe the table, key, and other aspects such as column renames etc.
I.e.
[Table("tblOrders", "App")] // tblOrders table in App namespace
public class Order
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int OrderId { get; set; }
[Column("OrderNum")]
public string OrderNumber { get; set; }
public string OrderRef { get; set; }
[ForeignKey("Customer")]
public int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
}
This works for the 90-%ile of cases where you want to set up entities. For simple columns that you don't need to rename etc. you don't need to add attributes and leave it to convention.
Entity Configuration: The commonly referenced means of doing this is to use the DbContext's OnModelCreating override and use modelBuilder to configure the entities. For smaller system with a couple handfuls of entities this can be manageable, but for larger systems this can get rather bloated since everything ends up in one method, or a chain of method calls to break it up.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Order>()
.ToTable("tblOrders", "App")
.HasKey(x => x.OrderId)
.Property(x => x.OrderId)
.HasDatabaseGenerated(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Order>()
.Property(x => x.OrderNumber)
.HasColumnName("OrderNum);
modelBuilder.Entity<Order>()
.HasRequired(x => x.Customer)
.WithMany(x => x.Orders)
.HasForeignKey(x => x.CustomerId);
}
The lesser documented option is to leverage EntityTypeConfigration<TEntity> (IEntityTypeConfiguration<TEntity> in EF Core)
public class OrderConfiguration : EntityTypeConfiguration<Order>
{
public OrderConfiguration()
{
ToTable("tblOrders", "App");
HasKey(x => x.OrderId)
.Property(x => x.OrderId)
.HasDatabaseGenerated(DatabaseGeneratedOption.Identity);
Property(x => x.OrderNumber)
.HasColumnName("OrderNum");
HasRequired(x => x.Customer)
.WithMany(x => x.Orders)
.HasForeignKey(x => x.CustomerId);
}
}
From there the DbContext just needs to be initialized to load the entity type configurations. This is done in the OnModelCreating which you can do explicitly, or add all Configurations by assembly.
modelBuilder.Configurations.AddFromAssembly(GetType().Assembly);
Personally, I default to declaring EntityTypeConfigurations for all entities as I prefer to rely on convention as little as possible. Being explicit with the configuration means you have something to investigate and work with where a convention doesn't work the way you expect, and it allows you to declare mappings for things like ForeignKeys without declaring FK properties in the entities. (Highly recommended to avoid two sources of truth about a relationship, being the FK and the navigation property)
My projects will commonly have a .Data project where I will keep the Entities, DbContext, and Repositories for a project. The EntityTypeConfiguration instances I place under /Entities/Configuration. They could just as easily be housed in the entity class files, as internal members of the entity class itself, or nested under the Entity class. (I.e. using a plugin like NestIn)
I have a Member named "Name" and I'm using AutoMapper to map between my ViewModel and my base Model. However, I also have a method named "GetName()" on a separate ViewModel which seems to be overriding my "Name" member's 'get' on the actual model.
I've since renamed the method to "GetFullName()" and this is no longer a problem.
This work-around works just fine, however, I would like to know what override in AutoMapper I can implement to let it know to not map function values like "GetName()" to a member's 'get'.
You can override via:
Mapper.CreateMap<Foo, FooDto>()
.ForMember(d => d.Name, opt => opt.MapFrom(src => src.Name));
Just as the title states, Can I add an extra property to one of my POCOs that does not map to a DB column(database was created first), and will not be persisted. This property will only be used within the application and never needs to be persisted.
Are there any extra measures to take to accomplish this besides defining the property as normal?
Yes, you absolutely can do that. Here's an example from a configuration class I have:
public class ForCommentEntities:EntityTypeConfiguration<Comment> {
public ForCommentEntities(String schemaName) {
this.HasRequired(e => e.SystemUser)
.WithMany()
.Map(m => m.MapKey("SystemUserID"));
this.Ignore(e => e.Remarks);
this.ToTable("Comment", schemaName);
}
}
The this.Ignore call is the important part. It takes a lambda expression to one of the properties on your class. This is part of what makes EFCF great (IMO) as it keeps configuration detail out of your POCOs.
The configuration class would be used like this in your Context:
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
var schemaName = Properties.Settings.Default.SchemaName;
modelBuilder.Configurations
.Add(new Configuration.ForCommentEntities(schemaName))
// ...other configuration options here
;
}
The nice part about Code First and POCO is you can now have business objects which are used by EF without the need of a mapper (e.g. AutoMapper or your own). Also means not having to decorate your objects with EF attributes and more (hence Yuck's answer above). However a additional advantage is, yes, the ability to add methods or properties to the object. An example would be a collection (e.g. addresses) and you would like to have a sorted or filtered projection. Another would be business rule validation before calling SaveChange(). As we all know, the possibilities are endless but the point is you can and should use these objects as business objects who get populated from your data layer.