Is it posible to create configuration for mapping specified objects for AutoMapper and CreateMap by passing this configuration as parameter?
For example. Property with configuration and creating map in constructor
public class BaseProfile : Profile
{
protected IMappingExpression<a, b> AB_Mapping { get; set; }
public BaseProfile()
{
CreateMap<a, b>(AB_Mapping);
}
}
Related
I have a 'master' Visual Studio project which contains Entity Framework mappings similar to:
public class UserMap : EntityTypeConfiguration<User>
{
public UserMap()
{
// Table Mapping
ToTable("Users");
this.Property(x => x.Username).HasColumnName("Username");
// Other mapping goes here
}
}
The User entity being mapped is just a simple POCO:
public class User {
public string Username { get; set; }
// Other properties omitted for brevity
}
I have a second 'child' VS project/application (which references the master project) which has the following ExtendedUser Entity/POCO which is also mapped using EF:
public class ExtendedUser : User {
// Extra navigation properties
public ICollection<Order> Orders { get; set; }
}
This entity doesn't have extra fields, but does have various relationship collections which are specific to that application and only that application.
My problem is that I would like to inherit the mapping defined for the User in the first VS project. The master User class is going to be used in several other projects so I need to avoid any duplication of mappings.
If I define the mapping as:
public class ExtendedUserMap : UserMap
{
public UserMap()
{
}
}
Then I can't reference any of the ExtendedUser properties as the mapping is of type EntityTypeConfiguration<User> not EntityTypeConfiguration<ExtendedUser>.
Obviously I can't inherit from two classes, so I am unsure of a suitable way to achieve what I want to do.
How can I define ExtendedUserMap such that I can use the User mappings and also include the navigation properties for ExtendedUser?
You can define your base mapping class slightly different:
public abstract class UserMapBase<TUser> : EntityTypeConfiguration<TUser>
where TUser : User
{
protected UserMapBase()
{
// Table Mapping
ToTable("Users");
this.Property(x => x.Username).HasColumnName("Username");
// Other mapping goes here
}
}
Now you can have a subclasses like so:
public class UserMap : UserMapBase<User>
{ }
public class ExtendedUserMap : UserMapBase<ExtendedUser>
{
public ExtendedUserMap()
{
// map ExtendedUser properties here.
}
}
Currently, I'm using ASP Identity with MVC 5.I want to remove phone number field from the AspNetUsers table, but when I use add-migration command it causes the following error.
You cannot use Ignore method on the property 'PhoneNumber' on type
'Models.DbModel.User' because this type inherits from the type
'Microsoft.AspNet.Identity.EntityFramework.IdentityUser`
I have already read tons of questions on here, but all of them said you have to ignore property in your base class, however, I don't have any access to the base in this case.
How can I solve this problem?
Update: when I used fluent API inside the OnModelCreating method it worked, I don't want to use it this way so I separated the config class for each entity.
Below is my code:
Derived Entity Class
public class User: IdentityUser
{
public ICollection<Comment> Comments { get; set; }
}
Config class
public sealed class UserConfig : EntityTypeConfiguration<User>
{
public UserConfig()
{
ToTable("dbo", "Users");
Ignore(x => x.PhoneNumber);
Ignore(x => x.PhoneNumberConfirmed);
}
}
Context Class
public class WebsiteContext : IdentityDbContext
{
public WebsiteContext()
: base("XYZ")
{
}
public DbSet<Comment> Comment { get; set; }
//public DbSet<User> User { get; set; }
public static WebsiteContext Create()
{
return new WebsiteContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new CommentConfig());
modelBuilder.Configurations.Add(new UserConfig());
}
}
Try the [NotMapped] attribute from
System.ComponentModel.DataAnnotations.Schema
This might get you around that limitation , it has been used to ignore Enums in the mapping, this might not be exactly what you want
Given the following model:
using NetTopologySuite.Geometries;
public class bounding_box
{
public virtual int id { get; protected set; }
public virtual Polygon area { get; set; }
}
How do I automap the area property to a area geometry(Polygon) column when generating the DB schema using Fluent Nhibernate? Note that I do not care about being able to read / update the geometry column using NHibernate since I will be using GDAL in my code.
I know I can do it by implementing a manual override, i.e.:
public class bounding_boxMappingOverrride : IAutoMappingOverride<bounding_box>
{
public void Override(AutoMapping<bounding_box> mapping)
{
mapping.Map(x => x.area)
.CustomSqlType("geometry(Polygon)");
}
}
However, I have many tables with geometry columns so I would much prefer to be able to specify a custom type mapping.
For some reason, the area property is never intercepted by the following property convention:
public class PostgisTypesConvention : IPropertyConvention
{
public void Apply(IPropertyInstance instance)
{
if (instance.Type == typeof(Polygon))
{
instance.CustomSqlType("geometry(Polygon)"); // Never reached
}
}
}
I have the same problem if I use GeoAPI.Geometries.IPolygon instead of NetTopologySuite.Geometries.Polygon...
I was finally able to resolve this by defining a custom UserTypeConvention, i.e.:
using NetTopologySuite.Geometries;
using NHibernate.Spatial.Type;
public class PostGisPolygonUserTypeConvention : UserTypeConvention<PostGisGeometryType>
{
public override void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
{
criteria.Expect(c => c.Type == typeof(Polygon));
}
public override void Apply(IPropertyInstance instance)
{
// Have to set CustomType to be able to read/write rows using NHibernate
instance.CustomType<PostGisGeometryType>();
// Have to set CustomSqlType to generate correct SQL schema
instance.CustomSqlType("geometry(Polygon)");
}
}
The same principle can also be used to create UserTypeConventions for other geometries, such as Point, LineString, MultiPoint, etc.
I have entity with nested collection and according model. Let's say:
class Entity
{
public IList<NestedEntity> Nested { get; set; }
}
and
class Model
{
public IList<NestedModel> Nested { get; set; }
}
and I need something like the following:
var existingEntity = service.GetEntity(id);
Mapper.Map<Model, Entity>(model, existingEntity);
// now existingEntity is an updated entity and we can save it
service.SaveEntity(existingEntity);
So while mapping nested collection mapper should remove the items which are not exist in existing entity, add which are newly created and just update the others.
How should I configure AutoMapper to reach such behavior?
I found that custom ValueResolvers ResolveCore method has no target class parameter so it can only create but not update collection.
Here is the solution for Model -> Entity mapping.
Mapper.CreateMap<NestedModel, NestedEntity>();
Mapper.CreateMap<Model, Entity>()
.ForMember(x => x.Nested, opt => opt.ResolveUsing<Resolver>());
public class Resolver : IValueResolver
{
public ResolutionResult Resolve(ResolutionResult source)
{
var targetCollection = ((Entity) source.Context.DestinationValue).Nested;
// TODO: Custom mapping here.
return source.New(targetCollection, typeof(NestedEntity[]));
}
}
I am trying to use a common EntityTypeConfiguration class to configure the primary key for all of my entities, so that each derived configuration class does not repeat itself. All of my entities implement a common interface IEntity (which says that each entity must have an Id property of type int).
My configuration base class looks like this:
public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
where TEntity : class , IEntity {
public EntityConfiguration() {
HasKey( e => e.Id );
Property( e => e.Id ).HasDatabaseGeneratedOption( DatabaseGeneratedOption.Identity );
}
}
Each entity then has it's own specific configuration class extending this one like this:
public class CustomerConfiguration : EntityConfiguration<Customer> {
public CustomerConfiguration() : base() {
// Entity specific configuration here
}
}
It compiles fine, but the problem I am having is that at runtime I get the following Exception being raised when EF 4.1 RC tries to create the model:
System.InvalidOperationException was
unhandled Message=The key component
'Id' is not a declared property on
type 'Customer'. Verify that it has
not been explicitly excluded from the
model and that it is a valid primitive
property. Source=EntityFramework
If I change the CustomerConfiguration class to extend from EntityTypeConfiguration<Customer> and repeat the primary key configuration then it works fine, but I lose the ability to share common configuration (DRY principal is the motivation).
Am I doing something wrong here?
Is there another way to share common configuration between entities?
For reference here are the other classes involved:
public interface IEntity {
int Id { get; set; }
}
public class Customer : IEntity {
public virtual int Id { get; set; }
public virtual string name { get; set; }
}
Thanks!
It looks like these configurations has some problem with interface. It works if you change IEntity to EntityBase:
public class EntityBase
{
public virtual int Id { get; set; }
}
public class Customer : EntityBase
{
public virtual string Name { get; set; }
}
public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
where TEntity : EntityBase
{
public EntityConfiguration()
{
HasKey(e => e.Id);
Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
public class CustomerConfiguration : EntityConfiguration<Customer>
{
public CustomerConfiguration()
: base()
{
...
}
}
I do not think that you need to go through all of this. EF 4.1 Code First uses a lot of convention over configuration and via this, the Id property of an entity is configured as the primary key. So by implementing the IEntity interface on your entities you are setting them up with the Id as the primary key.
Here is a link to the ADO.NET Team Blog that explains how the primary key convention works - Conventions for Code First
You could just create a static method on a class and pass the entity into it. For example:
public class CustomerConfiguration : EntityConfiguration<Customer>
{
public CustomerConfiguration()
: base()
{
...
EntityConfiguration.Configure(this);
}
}
public static class EntityConfiguration
{
public static void Configure<TEntity>(EntityTypeConfiguration<TEntity> entity) where TEntity : EntityBase
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
I have similar issue with EF5.0 when i have generic abstract class with Id property and implementation for abstract members and self defined properties.
look like entity framework code first is looking only for mapped class properties.
i have tried to use reflector - seems i am right, but don't sure about this for 100%.
And, fortunately, have found solution for this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
modelBuilder.Entity<MyEntity>()
.Map(m =>
{
**m.MapInheritedProperties();**
});
}
so in my case: to map also properties from base class i have to add one line of code m.MapInheritedProperties()...