How to use automapper? - automapper

I have domain class with following definition
public class Category : EntityBase<int>
{
public string Name { get; set; }
public string Description { get; set; }
}
And this class is inherited from a common abstract class
public abstract class EntityBase<TId>
{
public TId Id { get; set; }
}
And my ServiceModel class for this type is look like
public class CategoryDto
{
public string Name { get; set; }
public string Description { get; set; }
public int CategoryId { get; set; }
}
to convert between object i am using automapper. i configured automapper like this
public class AutoMapperServiceConfigurations
{
public static void Configure()
{
Mapper.Initialize(conf => conf.AddProfile(new CategoryProfile()));
}
}
public class CategoryProfile : Profile
{
protected override void Configure()
{
Mapper.CreateMap<Category,CategoryDto>();
}
}
to convert objects when i used automapper in my code it shows some error, my code is given below
var categoryCollection= _categoryRepository.Get<Category>();
// Mapping section here i got error
var returnCollection =
Mapper.Map<IQueryable<Category>, IQueryable<CategoryDto>> (categoryCollection);
return returnCollection;
and the error is
<Error><Message>An error has occurred.</Message><ExceptionMessage>
Unable to cast object of type
'System.Collections.Generic.List`1[PCD.Service.ServiceModels.CategoryDto]' to type 'System.Linq.IQueryable`1[PCD.Service.ServiceModels.CategoryDto]'.
</ExceptionMessage><ExceptionType>System.InvalidCastException</ExceptionType><StackTrace> at AutoMapper.MappingEngine.Map[TSource,TDestination](TSource source)
at AutoMapper.Mapper.Map[TSource,TDestination](TSource source)
at PCD.Service.Implimentations.CategoryService.Read[T]() in g:\AngularJs Practise\ProofOfConceptDemo.Solution\PCD.Service\Implimentations\CategoryService.cs:line 50
at PCD.WebApi.Controllers.CategoryController.Get() in g:\AngularJs Practise\ProofOfConceptDemo.Solution\PCD.WebApi\Controllers\CategoryController.cs:line 23
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass13.<GetExecutor>b__c(Object instance, Object[] methodParameters)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.<>c__DisplayClass5.<ExecuteAsync>b__4()
at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)</StackTrace></Error>

You will want to use the queryable extensions:
http://docs.automapper.org/en/stable/Queryable-Extensions.html
var categoryCollection = _categoryRepository.Get<Category>();
var returnCollection = categoryCollection.ProjectTo<CategoryDto>();
return returnCollection.ToList();

Related

autofac not resolve properly generic List type

I am trying to resolve list of object using autofac Container, and expecting an empty list in response. However, I am not able to get empty list in return instead getting count as 1.
I also try with without list registration in aotufac conatiner but getting same response.
<pre><code>
class autofacFactory : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterGeneric(typeof(List<>)).As(typeof(IList<>));
builder.RegisterType<Response>().As<IResponse>();
builder.RegisterType<CustomDependencyResolver>().As<ICustomDependencyResolver>();
}
}
public class Response : IResponse
{
public string TransactionNo { get; set; }
public string SchemeCode { get; set; }
}
public interface IResponse
{
string TransactionNo { get; set; }
string SchemeCode { get; set; }
}
public interface ICustomDependencyResolver
{
TResolved Resolve<TResolved>();
}
internal class CustomDependencyResolver : ICustomDependencyResolver
{
private readonly ILifetimeScope _lifetimeScope;
public CustomDependencyResolver(ILifetimeScope lifetimeScope)
{
_lifetimeScope = lifetimeScope;
}
public TResolved Resolve<TResolved>()
=> _lifetimeScope.Resolve<TResolved>();
}
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterModule(new autofacFactory());
using (var container = builder.Build())
{
ICustomDependencyResolver customDependencyResolver = container.Resolve<ICustomDependencyResolver>();
var collection = customDependencyResolver.Resolve<ICollection<IResponse>>();
var list = customDependencyResolver.Resolve<IList<IResponse>>();
}
}
Actual response:
[Image1][1]
[Image2][2]
[Expected Response][3]
[1]: https://i.stack.imgur.com/NVXeW.jpg
[2]: https://i.stack.imgur.com/k58QX.jpg
[3]: https://i.stack.imgur.com/EcFyc.jpg
Try not registering IList<> or List<> - Autofac has built-in support for that.

Assigning null to a foreign key in EntityFramework Code first approach

I want to make a virtual object (Details) to null, my sample Class details below:
public class test
{
public List<stud> students{get;set;}
}
public class stud
{
public int id{get;set;}
public string name{get;set;}
[ForeignKey("Details")]
public int DetailId { get; set; }
[JsonIgnore]
public virtual Details Details{ get; set; }
}
public class Details
{
public string a {get;set;}
public string b{get;set;}
}
test.students= await db.students.where(x=>x.id==12).ToListAsync();
foreach(var a in test.students)
{
a.Details=null;
db.savechanges();//but the Details obj is not being set to null.
}
Can someone please help me to set Details obj as null?

Azure Table Storage - TableEntity map column with a different name

I am using Azure Table Storage as my data sink for my Semantic Logging Application Block. When I call a log to be written by my custom EventSource, I get columns similar to the ff.:
EventId
Payload_username
Opcode
I can obtain these columns by creating a TableEntity class that matches the column names exactly (except for EventId, for some reason):
public class ReportLogEntity : TableEntity
{
public string EventId { get; set; }
public string Payload_username { get; set; }
public string Opcode { get; set; }
}
However, I would like to store the data in these columns in differently named properties in my TableEntity:
public class ReportLogEntity : TableEntity
{
public string Id { get; set; } // maps to "EventId"
public string Username { get; set; } // maps to "Payload_username"
public string Operation { get; set; } // maps to "Opcode"
}
Is there a mapper/attribute I can make use of to allow myself to have the column name different from the TableEntity property name?
You can override ReadEntity and WriteEntity methods of interface ITableEntity to customize your own property names.
public class ReportLogEntity : TableEntity
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public string Id { get; set; } // maps to "EventId"
public string Username { get; set; } // maps to "Payload_username"
public string Operation { get; set; } // maps to "Opcode"
public override void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
{
this.PartitionKey = properties["PartitionKey"].StringValue;
this.RowKey = properties["RowKey"].StringValue;
this.Id = properties["EventId"].StringValue;
this.Username = properties["Payload_username"].StringValue;
this.Operation = properties["Opcode"].StringValue;
}
public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
{
var properties = new Dictionary<string, EntityProperty>();
properties.Add("PartitionKey", new EntityProperty(this.PartitionKey));
properties.Add("RowKey", new EntityProperty(this.RowKey));
properties.Add("EventId", new EntityProperty(this.Id));
properties.Add("Payload_username", new EntityProperty(this.Username));
properties.Add("Opcode", new EntityProperty(this.Operation));
return properties;
}
}

Nhibernate confused by class inheritance and returns mixed results

I have a class with a few properties and some methods
public class Content
{
public int Id { get; set; }
public string Application { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public override bool Equals(object obj) {...}
public override int GetHashCode() {...}
}
With this Fluent NHibernate mapping:
public class ContentMapping : ClassMap<Content>
{
public ContentMapping()
{
Table("vw_all_contents");
CompositeId()
.KeyProperty(x => x.Id, "id")
.KeyProperty(x => x.Application, "application");
Map(x => x.Property1, "property1");
Map(x => x.Property2, "property2");
}
}
Up to here everything works fine.
I now want to populate the same object but with a table a federated table that connects to another database.
So I have:
public class ContentOnProductionDatabase : Content { }
With a mapping:
public class ContenOnProductionDatabasetMapping : ClassMap<ContentOnProductionDatabase>
{
public ContentOnProductionDatabaseMapping()
{
Table("vw_federated_all_contents");
CompositeId()
.KeyProperty(x => x.Id, "id")
.KeyProperty(x => x.Application, "application");
Map(x => x.Property1, "property1");
Map(x => x.Property2, "property2");
}
}
And here is where NHibernate gets really confused and the queries return mixed results from both databases.
The problem goes away if my ContentOnProductionDatabase does not extend Content but instead is a duplicate class like this:
public class ContentOnProductionDatabaseMapping
{
public int Id { get; set; }
public string Application { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public override bool Equals(object obj) {...}
public override int GetHashCode() {...}
}
So now everything is fine but I don't like the fact that there is so much code duplication and it seems to me there must be some sort of Mapping configuration out there to force NHibernate to ignore the inheritance and differentiate the two, especially since they map to different databases.
The repository framework is an inbuilt one handles the session and the queries.
public class ContentRepository : NHibernateRepositoryBase, IContentRepository
{
public ContentRepository(INHibernateContext context, ISettingsManager settingsManager): base(context){ }
public Content ReadContent(int id, string application)
{
using (ISessionContainer container = Context.GetSessionContainer())
{
return
container.AsQueryable<Content>()
.FirstOrDefault(c => c.Id == id && c.Application == application);
// All queries using <Content> return the correct results
}
}
public ContentOnProductionDataBase ReadFederatedContent(int id, string application)
{
using (ISessionContainer container = Context.GetSessionContainer())
{
return
container.AsQueryable<ContentOnProductionDataBase>()
.FirstOrDefault(c => c.Id == id && c.Application == application);
// All queries using <ContentOnProductionDataBase> return the combined results of <Content> and <ContentOnProductionDataBase>
}
}
}
Internally the container.AsQueryable works by invoking this:
public IQueryable<TEntity> AsQueryable<TEntity>() where TEntity : class
{
return LinqExtensionMethods.Query<TEntity>(this.Session);
}
Any ideas how to get rid of the code duplication?
To define the class mapping and the properties only once, you have to define a base class and define the mapping with UseUnionSubclassForInheritanceMapping which will allow you to use independent tables per entity which is derived from that base class.
You don't have to but you should declare your base class as abstract, because it will not have a database representation. So persisting the base class will fail! Meaning, you don't want anyone to use it as an entity, instead use your derived classes...
To do so, create one base, and 2 derived classes which should be stored in one table per class.
public abstract class ContentBase
{
public virtual int Id { get; set; }
public virtual string Application { get; set; }
public virtual string Property1 { get; set; }
public virtual string Property2 { get; set; }
public override bool Equals(object obj)
{
[..]
}
public override int GetHashCode()
{
[..]
}
}
public class Content : ContentBase
{
}
public class ContentOnProductionDatabaset : ContentBase
{
}
The mapping of the base class must call UseUnionSubclassForInheritanceMapping, otherwise nHibernate would combine the classes.
public class ContentBaseMapping : ClassMap<ContentBase>
{
public ContentBaseMapping()
{
UseUnionSubclassForInheritanceMapping();
CompositeId()
.KeyProperty(x => x.Id, "id")
.KeyProperty(x => x.Application, "application");
Map(x => x.Property1, "property1");
Map(x => x.Property2, "property2");
}
}
The subclass mappings just have to define that the base is abstract.
Here you can also define each table name the entity should use.
public class ContentMapping : SubclassMap<Content>
{
public ContentMapping()
{
Table("vw_all_contents");
Abstract();
}
}
public class ContentOnProductionDatabaseMapping : SubclassMap<ContentOnProductionDatabaset>
{
public ContentOnProductionDatabaseMapping()
{
Table("vw_federated_all_contents");
Abstract();
}
}

AutoMapper - How to map a concrete domain class to an inherited destination DTO class?

I have a flat domain class like this:
public class ProductDomain
{
public int ID { get; set; }
public string Manufacturer { get; set; }
public string Model { get; set; }
public string Description { get; set; }
public string Price { get; set; }
}
I have two DTO classes like this:
public class ProductInfoDTO
{
public int ID { get; set; }
public string Manufacturer { get; set; }
public string Model{ get; set; }
}
public class ProductDTO : ProductInfoDTO
{
public string Description { get; set; }
public string Price { get; set; }
}
Now the problem is:
Scenario #1:
Mapper.CreateMap<ProductDomain, ProductInfoDTO>() // this mapping works fine
Scenario #2:
Mapper.CreateMap<ProductDomain, ProductDTO>() // this mapping is not working and throws System.TypeInitializationException
So my question is how to create mapping between ProductDomain and ProductDTO (which inherits ProductInfoDTO) without breaking the definition of both source and destination classes. Also I dont want to introduce any new inheritance for the domain class ProductDomain.
Thanks
You can build your own custom TypeConverter like this
public class ProductDomainToProductDTOConverter : ITypeConverter<ProductDomain, ProductDTO>
{
public ProductDTO Convert(ProductDomain source)
{
ProductDTO product = new ProductDTO();
product.Price = source.Price;
...
return product;
}
}
And then create a map with your custom TypeConverter like this
Mapper.CreateMap<ProductDomain, ProductDTO>().ConvertUsing<ProductDomainToProductDTOConverter>();

Resources