I'm trying to map an enum field to a dto property. I'm using PositionalToBeanResultTransformer, something like this:
PositionalToBeanResultTransformer trans = new PositionalToBeanResultTransformer(typeof(DTOClass), new string[] { "Id", "EnumProperty" });
var data = Sesion.CreateSQLQuery("SELECT Id, EnumField FROM Table")
.AddScalar("EnumField", NHibernateUtil.Custom(typeof(Enumerador)))
.SetResultTransformer(trans)
.List<DTOClass>();
public class DTOClass
{
public int Id { get; set; }
public Enumerador EnumProperty { get; set; }
}
the DTOClass is not mapped so I can't use AddEntity() and the code with AddScalar() throws an error that I must implement NHibernate.UserTypes.IUserType.
How can I convert the string field of the DB to an enum in a SQLQuery?
Thanks in advance for the help.
If you are not using AutoMapping, in your ClassMap add a similar line like below:
Table("MyClass");
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Type).CustomType(typeof(Enumerations.MyType));
public virtual int Id { get; set; }
public virtual Enumerations.MyType Type { get; set; }
I usually store my enums as integers in the DB and the ClassMap will appropriately map back to the enumeration.
Related
I'm making a list of checkboxes to update a user's roles, and I'm trying to map from this:
public class ApplicationRoleViewModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public string NormalizedName { get; set; }
public string ConcurrencyStamp { get; set; }
public int SortOrder { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
public string Icon { get; set; } // Font Awesome-ikoner, f.eks. "fa-user"
}
to this:
public class SelectableRoleViewModel
{
public Guid Id { get; set; }
public string DisplayName { get; set; }
public bool Selected { get; set; }
}
This is my mapping:
CreateMap<ApplicationRoleViewModel, SelectableRoleViewModel>()
.ForMember(dest => dest.Id, s => s.MapFrom(i => i.Id))
.ForMember(dest => dest.DisplayName, s => s.MapFrom(d => d.DisplayName))
.ForMember(dest => dest.Selected, i => i.Ignore());
Mapping it like this in the controller:
ApplicationRole role = await db.Roles.FirstOrDefaultAsync();
SelectableRoleViewModel sr = auto.Map<SelectableRoleViewModel>(role);
gives me the following error message:
AutoMapperMappingException: Missing type map configuration or unsupported mapping.
I am registering AutoMapper in Startup.cs like this:
services.AddAutoMapper(typeof(Startup));
Then, in AutoMapperProfile.cs:
public class AutomapperProfile : Profile
{
public AutomapperProfile()
{
// This is not working:
CreateMap<ApplicationRoleViewModel, SelectableRoleViewModel>()
.ForMember(dest => dest.Selected, i => i.Ignore());
// This is working:
CreateMap<ApplicationUser, ApplicationUserViewModel>();
// Many more mappings, all working
}
}
How can I get it to work?
The code you specified seems to be correct.
I will just suggest to remove the ForMember method for properties with the same names as auto mapper handles it automatically:
CreateMap<ApplicationRoleViewModel, SelectableRoleViewModel>()
.ForMember(dest => dest.Selected, i => i.Ignore());
The problem seems to be because you are not using the mapper right. Where have you registered the mapper? Is the registration happens before the map? Did you do it in the Startup? If you specify more code, it will be easier to help.
UPDATE:
After getting more code & info, the problem was that the map worked on a different object, ApplicationRoleViewModel and not ApplicationRole.
Just to see a difference ;)
public static SelectableRoleViewModel ToSelectable(this ApplicationRoleViewModel model)
{
return new SelectableRoleViewModel
{
Id = model.Id,
DisplayName = model.DisplayName
};
}
// Usage
var selectable = applicationRole.ToSelectable();
Type it once
Perfectly testable
Fully maintainable - supports all kinds of conversion/mapping
Reduce amount of injected dependencies and abstractions (mapper)
No extra dependencies on third party libraries
I need to configure NHibernate Mappings using Fluent library for some relations of my DB.
I created a Web Api MVC Project on VS 2017 with NHibernate v4.1.1.4000 and FluentNHibernate v2.0.3.
I've those tables:
Typology (Id, Description, ..., ExpressionId)
Expression (Id, Name, Script, Language)
Relations:
1 Typology can reference 0 or 1 Expression
1 Expression can be referenced by 0 or N Typology
I need to configure mappings so that manipulating the objects I can:
Change the Expression referenced on a Typology, and update it so that on the DB the value of ExpressionId column changes.
Delete a reference to an Expression on a Typology, so that the ExpressionId will be NULL and the corresponding Expression remains on the DB, even if it is not referenced by any other Typology.
Create a new Expression object and associate it to an existing (or newly created) Typology so that the new Expression is saved to DB and Typology (eventually created) reference it, like this:
Typology typology = _repositoryTypologies.GetById(1);
Expression newExp = new Expression()
{
Name = "S2",
Script = "public void Test()",
//...
Language = "cs"
};
typology.CompletionScript = newExp;
_repositoryTypologies.Save(typology);
If possible, if I delete an Expression, all the Typologies that reference it, will be updated with ExpressionId = NULL.
I already tried with some mappings but I didn't obtained the desired results.
I've been looking a bit here and there but I don't understand yet what is the best mapping for this case. Someone uses References() even if there's a 0-1 relation, someone else recommend to use HasOne()/HasMany().
These are my actual classes:
public class Typology
{
[Key]
public virtual int Id { get; protected set; }
[Required]
public virtual string Description { get; set; }
//...
public virtual Expression CompletionScript { get; set; }
}
public class TypologyMap : ClassMap<Typology>
{
public TypologyMap()
{
Table("Typologies");
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity().Column("TypologyId");
Map(x => x.Description).Column("Description").Not.Nullable();
//...
HasOne(x => x.CompletionScript).Cascade.SaveUpdate();
}
}
public class Expression
{
[Key]
public virtual int Id { get; protected set; }
[Required]
public virtual string Name { get; set; }
public virtual string Script { get; set; }
public virtual string Language { get; set; }
}
public class ExpressionMap : ClassMap<Expression>
{
public ExpressionMap()
{
Table("Expressions");
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity().Column("ExpressionId");
Map(x => x.Name).Column("Name").Not.Nullable();
Map(x => x.Script);
Map(x => x.Language);
}
}
Your Expression will need some kind of collection for its related Topologies. Something like this:
public class Expression
{
[Key]
public virtual int Id { get; protected set; }
[Required]
public virtual string Name { get; set; }
public virtual string Script { get; set; }
public virtual string Language { get; set; }
// At its most basic...
public virtual List<Topology> Topologies { get; set; }
}
Then you can map it:
public class ExpressionMap : ClassMap<Expression>
{
public ExpressionMap()
{
Table("Expressions");
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity().Column("ExpressionId");
Map(x => x.Name).Column("Name").Not.Nullable();
Map(x => x.Script);
Map(x => x.Language);
HasMany(x => x.Topologies);
}
}
You should be able to use References() on the Expression side of the mapping. Although some might recommend ManyToOne(). I'm not too sure of their nuances.
While this should provide a functional solution, you'll need to toughen it up a bit by considering access to the collection, cascading, etc.
I am a newbie to the Automapper framework. I have a domain class and a DTO class as follows:
public class Employee
{
public long Id {get;set;}
public string Name {get;set;}
public string Phone {get;set;}
public string Fax {get;set;}
public DateTime DateOfBirth {get;set;}
}
public class EmployeeDto
{
public long Id {get;set;}
public string FullName {get;set;}
public DateTime DateOfBirth {get;set;}
}
Note: The name of property "Name" of Employee class is not the same as that of property "FullName" of EmployeeDto class.
And here's the code to map the Employee object to EmployeeDto:
Mapper.CreateMap<Employee, EmployeeDto>(); // code line (***)
EmployeeDto dto = Mapper.Map<Employee, EmployeeDto>(employee);
My question is: If I want to map Employee (source class) to EmployeeDto (destination class), how can I specify the mapping rule? In other words, how should I do more with code line (***) above?
Never mind, I myself found a solution:
Mapper.CreateMap<Employee, EmployeeDto>()
.ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.Name));
Just to roll the comments above into an updated approach using Automapper 8.1+...
var mapConfig = new MapperConfiguration(
cfg => cfg.CreateMap<Employee, EmployeeDto>()
.ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.Name))
);
Then you would build the mapper using the mapConfig:
var mapper = mapConfig.CreateMapper();
We can also specify on Class attributes for mapping
From https://docs.automapper.org/en/stable/Conventions.html#attribute-support
Attribute Support
AddMemberConfiguration().AddName<SourceToDestinationNameMapperAttributesMember>();
* Currently is always on
Looks for instances of SourceToDestinationMapperAttribute for
Properties/Fields and calls user defined isMatch function to find
member matches.
MapToAttribute is one of them which will match the property based on
name provided.
public class Foo
{
[MapTo("SourceOfBar")]
public int Bar { get; set; }
}
Considering that we have two classes
public class LookupDetailsBO
{
public int ID { get; set; }
public string Description { get; set; }
}
and the other class is
public class MaterialBO
{
[MapTo(nameof(LookupDetailsBO.ID))]
public int MaterialId { get; set; }
[MapTo(nameof(LookupDetailsBO.Description))]
public string MaterialName { get; set; }
public int LanguageId { get; set; }
}
In this way you know typically to which property you follow .
and you make sure of the naming convention , so if you have changed the propery name in the source . The MapTo() will prompt an error
The new style of Attribute Mapping via Data Annotations:
https://docs.automapper.org/en/v8.1.0/Attribute-mapping.html?highlight=annotation
[AutoMap(typeof(Order))]
public class OrderDto {
// This is equivalent to a CreateMap<Order, OrderDto>()
For mapping the member
[SourceMember(nameof(Order.OrderTotal))]
public decimal Total { get; set; }
If you want reverse map then you add that property in
[AutoMap(typeof(Order), ReverseMap = true )]
public class OrderDto {
// This is equivalent to a CreateMap<Order, OrderDto>().ReverseMap()
The above answers are great and hope OP has got his answer. I just want to add how we can map fixed values instead of fields using UseValue() method of IMemberConfigurationExpression Interface.
Mapper.CreateMap<Employee, EmployeeDto>()
.ForMember(dest => dest.Department, opt => opt.UseValue("Development"));
This will map "Development" as a Department property value for destination data.
Looks a common situation to me: I have two tables:
documents:
dID (pk, int), dName(varchar)
and document_options:
dID (int), oType(int), oValue(varchar)
I would like to have a class Document with a property Options (a List of DocumentOption class)
Since document_options has no PK I cannot use HasMany, and rows from this table don't seem like 'real' entities anyway...
I see a way to generate an auto-number key for document options and map with HasMany, or maybe create a composite ID, but I'd like to know if there is a better option that I don't know about.
In this case, DocumentOptions is a value object, since it has no identity of its own and has no meaning outside of the document it belongs to. So, you would use Component to map the collection properties to the value object.
public class Document : Entity // don't worry about Entity; it's a base type I created that contains the Id property
{
public virtual string Name { get; set; }
public virtual IList<DocumentOptions> Options { get; protected set; }
public Document()
{
Options = new List<DocumentOptions>();
}
}
public class DocumentOptions
{
public virtual int Type { get; set; }
public virtual string Value { get; set; }
}
And the mapping:
public DocumentMap()
{
Table("documents");
Id(c => c.Id)
.Column("dId")
.GeneratedBy.HiLo("10");
Map(c => c.Name)
.Column("dName");
HasMany(c => c.Options)
.Component(c =>
{
c.Map(c2 => c2.Value).Column("oValue");
c.Map(c2 => c2.Type).Column("oType");
})
.Table("document_options")
.KeyColumn("dId")
.Cascade.AllDeleteOrphan();
}
If I understand correctly I had to map options as a list of components:
HasMany(x => x.DocumentOptions)
.Table("document_options")
.KeyColumn("dID")
.Component(c => {
c.Map(x => x.Option, "oID");
c.Map(x => x.Value, "oValue");
})
.Fetch.Subselect(); //This type of join isn't strictly needed, is used for SQL optimization
classes FYI:
public class Options {
public virtual int Option { get; set; }
public virtual int Value { get; set; }
}
public class Document {
public virtual int ID { get; set; }
public virtual String Name { get; set; }
public virtual IList<DocumentOption> DocumentOptions { get; set; }
}
I have created 3 tables in my database and put data into them. The 3 tables all have foreign keys joining them together. Below are the table classes and there mappings. When I run the query listed at the end I get IList<> of the objects and they have the data from all 3 tables. However, my HQL query is only from the top most table. How can I get back just the results from the top most table?
These are my classes:
public class Technology
{
public virtual int Id { get; private set; }
public virtual string Name { get; set; }
public virtual int SortOrder { get; set; }
public virtual string Abbreviation { get; set; }
public virtual IList<TechnologyDescription> TechnologyDescriptions { get; private set; }
public Technology()
{
TechnologyDescriptions = new List<TechnologyDescription>();
}
public virtual void AddTechnologyDescription(TechnologyDescription technologyDescription)
{
technologyDescription.Technology = this;
TechnologyDescriptions.Add(technologyDescription);
}
}
public class TechnologyDescription
{
public virtual int Id { get; private set; }
public virtual Technology Technology { get; set; }
public virtual string Description { get; set; }
public virtual DescriptionType DescriptionType { get; set; }
}
public class DescriptionType
{
public virtual int Id {get; private set;}
public virtual string Type { get; set; }
}
These are my mapping objects:
public class TechnologyMap : ClassMap<Technology>
{
public TechnologyMap()
{
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.SortOrder);
Map(x => x.Abbreviation);
HasMany(x => x.TechnologyDescriptions)
.Inverse()
.Cascade.All();
}
}
public class TechnologyDescriptionMap : ClassMap<TechnologyDescription>
{
public TechnologyDescriptionMap()
{
Id(x => x.Id);
References(x => x.Technology);
Map(x => x.Description);
References(x => x.DescriptionType);
}
}
public class DescriptionTypeMap : ClassMap<DescriptionType>
{
public DescriptionTypeMap()
{
Id(x => x.Id);
Map(x => x.Type);
}
}
And this is my HQL code:
IQuery q = session.CreateQuery("from Technology T");
IList technologies = q.List();
I don't know if it is possible using HQL, but using NHibernate's Criteria API, you can do this:
ICriteria criteria = session.CreateCriteria (typeof(Technology));
criteria.SetFetchMode ("TechnologyDescriptions", FetchMode.Lazy);
var list = criteria.List<Technology>();
However, this is probably not really what you want. The TechnologyDescriptions won't be fetched right now, but they will be fetched once you access them (that is: the first time you call the TechnologyDescriptions property).
When working with NHibernate, you shouldn't think in terms of 'data'. Rather, you should think in terms of 'entities'.
When retrieving an entity, you want to retrieve the entity entirly (directly, or in a lazy fashion). It is not possible to retrieve an entity partially, and this is quite obvious;
What should NHibernate do with an entity that you've retrieved partially, when you try to save that entity ?
Something else that pops in my mind:
I suppose you want to retrieve the Technologies, and nothing related because you want to display them in an overview or something like that ?
In such case, you should take a look at 'Transformations'.
You could for instance create an additional class which is called TechnologyView, which looks like this:
public class TechnologyView
{
public int Id
{
get;
private set;
}
public string Name
{
get;
private set;
}
public string Abbreviation
{
get;
private set;
}
private TechnologyView()
{
// Private constructor, required for NH
}
public TechnologyView( int id, string name, string abbreviation )
{
this.Id = id;
this.Name = name;
this.Abbreviation = abbreviation;
}
}
Once you've done this, you must inform NHibernate about the existance of this class.
You do this by Importing the class in an hbm.xml file for instance . (I do not know how to do it using Fluent).
<import class="MyNamespace.TechnologyView" />
After that, you can create a query (using HQL or Criteria) which retrieves TechnologyView instances. NHibernate is smart enough to generate a performant SQL query.
using HQL:
IQuery q = s.CreateQuery ("select new TechnologyView (t.Id, t.Name, t.Abbreviation) from Technology t");
using Criteria:
ICriteria criteria = s.CreateCriteria (typeof(Technology));
criteria.SetResultTransformer (Transformers.AliasToBean (typeof(TechnologyView));
var result = criteria.List<TechnologyView>();
I think what you're looking for is for the TechnologyDescriptions to be lazy loaded. That way the descriptions get loaded from the database only when they are accessed (NHibernate will issue a second db query. Note that this can lead to N+1 selects in some situations and you might prefer the all at once query depending on the usage.)
By NHibernate xml mappings default to lazy loading of collections. In the past it seems that the Fluent NHibernate did not have the same default. You need to add .LazyLoad() to the mapping.
Recently it looks like lazy loading has become the default fluent mapping:
Is the default behavior with Fluent NHibernate to lazy load HasMany<T> collections?