I have a property of a class that is mapped to another class that can't be stored in the database and can't be serialized; it implements the state pattern.
So I have something like this:
public IState MyState { get; set; }
Where I have two different states
public class LockedState : IState ...
public class UnlockedState : IState ...
In the database I need to persist the name of the current state that can be accomplished using, for example:
string name = myState.GetType().Name;
Do I have to write a custom and verbose IUserState or is there anything around?
In order to do that I had to implement a custom IUserType in the following way:
public sealed class StateMapper : IUserType
// get
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
string objectName = (string)NHibernateUtil.String.NullSafeGet(rs, names[0]);
Type stateType = Type.GetType(objectName, false, true);
if (stateType == null)
{
return null;
}
// StateFacility is used by my code to create a new Type
return StateFacility.CreateState(stateType);
}
// set
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
if (value == null)
{
NHibernateUtil.String.NullSafeSet(cmd, null, index);
return;
}
NHibernateUtil.String.NullSafeSet(cmd, value, index);
}
Related
With a simple class/interface like this
public interface IThing
{
string Name { get; set; }
}
public class Thing : IThing
{
public int Id { get; set; }
public string Name { get; set; }
}
How can I get the JSON string with only the "Name" property (only the properties of the underlying interface) ?
Actually, when i make that :
var serialized = JsonConvert.SerializeObject((IThing)theObjToSerialize, Formatting.Indented);
Console.WriteLine(serialized);
I get the full object as JSON (Id + Name);
The method I use,
public class InterfaceContractResolver : DefaultContractResolver
{
private readonly Type _InterfaceType;
public InterfaceContractResolver (Type InterfaceType)
{
_InterfaceType = InterfaceType;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
//IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
IList<JsonProperty> properties = base.CreateProperties(_InterfaceType, memberSerialization);
return properties;
}
}
// To serialize do this:
var settings = new JsonSerializerSettings() {
ContractResolver = new InterfaceContractResolver (typeof(IThing))
};
string json = JsonConvert.SerializeObject(theObjToSerialize, settings);
Improved version with nested interfaces + support for xsd.exe objects
Yet another variation here. The code came from http://www.tomdupont.net/2015/09/how-to-only-serialize-interface.html with the following improvements over other answers here
Handles hierarchy, so if you have an Interface2[] within an Interface1 then it will get serialized.
I was trying to serialize a WCF proxy object and the resultant JSON came up as {}. Turned out all properties were set to Ignore=true so I had to add a loop to set them all to not being ignored.
public class InterfaceContractResolver : DefaultContractResolver
{
private readonly Type[] _interfaceTypes;
private readonly ConcurrentDictionary<Type, Type> _typeToSerializeMap;
public InterfaceContractResolver(params Type[] interfaceTypes)
{
_interfaceTypes = interfaceTypes;
_typeToSerializeMap = new ConcurrentDictionary<Type, Type>();
}
protected override IList<JsonProperty> CreateProperties(
Type type,
MemberSerialization memberSerialization)
{
var typeToSerialize = _typeToSerializeMap.GetOrAdd(
type,
t => _interfaceTypes.FirstOrDefault(
it => it.IsAssignableFrom(t)) ?? t);
var props = base.CreateProperties(typeToSerialize, memberSerialization);
// mark all props as not ignored
foreach (var prop in props)
{
prop.Ignored = false;
}
return props;
}
}
Inspired by #user3161686, here's a small modification to InterfaceContractResolver:
public class InterfaceContractResolver<TInterface> : DefaultContractResolver where TInterface : class
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(typeof(TInterface), memberSerialization);
return properties;
}
}
You can use conditional serialization. Take a look at this link. Basicly, you need to implement the IContractResolver interface, overload the ShouldSerialize method and pass your resolver to the constructor of the Json Serializer.
An alternative to [JsonIgnore] are the [DataContract] and [DataMember] attributes. If you class is tagged with [DataContract] the serializer will only process properties tagged with the [DataMember] attribute (JsonIgnore is an "opt-out" model while DataContract is "op-in").
[DataContract]
public class Thing : IThing
{
[DataMember]
public int Id { get; set; }
public string Name { get; set; }
}
The limitation of both approaches is that they must be implemented in the class, you cannot add them to the interface definition.
You can add the [JsonIgnore] annotation to ignore an attribute.
I'd like to share what we ended up doing when confronted with this task. Given the OP's interface and class...
public interface IThing
{
string Name { get; set; }
}
public class Thing : IThing
{
public int Id { get; set; }
public string Name { get; set; }
}
...we created a class that is the direct implementation of the interface...
public class DirectThing : IThing
{
public string Name { get; set; }
}
Then simply serialized our Thing instance, deserialized it as a DirectThing, then Serialized it as a DirectThing:
var thing = new Thing();
JsonConvert.SerializeObject(
JsonConvert.DeserializeObject<DirectThing>(JsonConvert.SerializeObject(thing)));
This approach can work with a long interface inheritance chain...you just need to make a direct class (DirectThing in this example) at the level of interest. No need to worry about reflection or attributes.
From a maintenance perspective, the DirectThing class is easy to maintain if you add members to IThing because the compiler will give errors if you haven't also put them in DirectThing. However, if you remove a member X from IThing and put it in Thing instead, then you'll have to remember to remove it from DirectThing or else X would be in the end result.
From a performance perspective there are three (de)serialization operations happening here instead of one, so depending on your situation you might like to evaluate the performance difference of reflector/attribute-based solutions versus this solution. In my case I was just doing this on a small scale, so I wasn't concerned about potential losses of some micro/milliseconds.
Hope that helps someone!
in addition to the answer given by #monrow you can use the default [DataContract] and [DataMember]
have a look at this
http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx
Finally I got when it will not work...
If you want to have inside another complex object it will not be properly serialized.
So I have made version which will extract only data stored in specific assembly and for types which have the same base interface.
So it is made as .Net Core JsonContractResolver.
In addition to data extraction it solves:
a) camelCase conversion before sending data to client
b) uses top most interface from allowed scope (by assembly)
c) fixes order of fields: field from most base class will be listed first and nested object will meet this rule as well.
public class OutputJsonResolver : DefaultContractResolver
{
#region Static Members
private static readonly object syncTargets = new object();
private static readonly Dictionary<Type, IList<JsonProperty>> Targets = new Dictionary<Type, IList<JsonProperty>>();
private static readonly Assembly CommonAssembly = typeof(ICommon).Assembly;
#endregion
#region Override Members
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
if (type.Assembly != OutputJsonResolver.CommonAssembly)
return base.CreateProperties(type, memberSerialization);
IList<JsonProperty> properties;
if (OutputJsonResolver.Targets.TryGetValue(type, out properties) == false)
{
lock (OutputJsonResolver.syncTargets)
{
if (OutputJsonResolver.Targets.ContainsKey(type) == false)
{
properties = this.CreateCustomProperties(type, memberSerialization);
OutputJsonResolver.Targets[type] = properties;
}
}
}
return properties;
}
protected override string ResolvePropertyName(string propertyName)
{
return propertyName.ToCase(Casing.Camel);
}
#endregion
#region Assistants
private IList<JsonProperty> CreateCustomProperties(Type type, MemberSerialization memberSerialization)
{
// Hierarchy
IReadOnlyList<Type> types = this.GetTypes(type);
// Head
Type head = types.OrderByDescending(item => item.GetInterfaces().Length).FirstOrDefault();
// Sources
IList<JsonProperty> sources = base.CreateProperties(head, memberSerialization);
// Targets
IList<JsonProperty> targets = new List<JsonProperty>(sources.Count);
// Repository
IReadOnlyDistribution<Type, JsonProperty> repository = sources.ToDistribution(item => item.DeclaringType);
foreach (Type current in types.Reverse())
{
IReadOnlyPage<JsonProperty> page;
if (repository.TryGetValue(current, out page) == true)
targets.AddRange(page);
}
return targets;
}
private IReadOnlyList<Type> GetTypes(Type type)
{
List<Type> types = new List<Type>();
if (type.IsInterface == true)
types.Add(type);
types.AddRange(type.GetInterfaces());
return types;
}
#endregion
}
I am using ValueInjecter to map properties from a Domain model to a DTO served up via a Service Layer. The service in question also accepts updates... so an updated DTO is passed in and this is then injected to the domain object and saved.
// Domain
public class Member
{
public Country Country { get; set; }
}
public class Country
{
public string Code { get; set; }
public string Name { get; set; }
}
//Dto
public class MemberDto
{
public string CountryCode { get; set; }
}
//Transformation Method attempt 1
public Member InjectFromDto (MemberDto dto, Member source)
{
source = source.InjectFrom<UnflatLoopValueInjection>(dto);
return source;
}
Now all this above code does is updates the Property Member.Country.Code which is obviously not what I need it to do.
So from the docs, I figured I needed to create an override and got this:
public class CountryLookup: UnflatLoopValueInjection<string, Country>
{
protected override Country SetValue(string sourcePropertyValue)
{
return countryService.LookupCode(sourcePropertyValue);
}
}
//revised transformation call
//Transformation Method attempt 2
public Member InjectFromDto (MemberDto dto, Member source)
{
source = source.InjectFrom<UnflatLoopValueInjection>(dto)
.InjectFrom<CountryLookup>(dto);
return source;
}
My problem is during debugging, CountryLookup never gets called.
Possible reasons I can think of:
Nhibernate Proxy classes causing value injecter to not match the Country type? Tho this doesnt make sense because it works during the flattening.
Perhaps the unflattening isn't firing for some reason. I.e Dto is CountryCode and Domain is Country.Code
I need to use the CountryCode property on the Dto to call a countryService.LookupCode to return the correct object to use during the update injection.
unflattening would be to do this:
entity.Country.Code <- dto.CountryCode
what you need is:
entity.Country <- dto.CountryCode
so the solution for you would be to inherit an ExactValueInjection where you would go from CountryCode to Country.
what I recommend you to do is do the same that I did in the live demo of another project of mine http://awesome.codeplex.com
where I have something like this:
public class Entity
{
public int Id{get;set;}
}
public class Member : Entity
{
public Country Country{get;set;}
}
public class MemberDto : DtoWithId
{
public int? Country {get;set;}
}
and use these injections to go from entity to dto and back
public class NullIntToEntity : LoopValueInjection
{
protected override bool TypesMatch(Type sourceType, Type targetType)
{
return sourceType == typeof(int?) && targetType.IsSubclassOf(typeof(Entity));
}
protected override object SetValue(object sourcePropertyValue)
{
if (sourcePropertyValue == null) return null;
var id = ((int?) sourcePropertyValue).Value;
dynamic repo = IoC.Resolve(typeof(IRepo<>).MakeGenericType(TargetPropType));
return repo.Get(id);
}
}
//(you also need to have a generic repository, notice IRepo<>)
public class EntityToNullInt : LoopValueInjection
{
protected override bool TypesMatch(Type sourceType, Type targetType)
{
return sourceType.IsSubclassOf(typeof (Entity)) && targetType == typeof (int?);
}
protected override object SetValue(object o)
{
if (o == null) return null;
return (o as Entity).Id;
}
}
these injections will handle not just going from int? to Country and back but also any other type which inherits Entity
Using the suggestion/reference from Omu this was the specific code to the problem.
public class CountryLookup : ExactValueInjection
{
private ICountryService countryservice;
public CountryLookup(ICountryService countryService)
{
this.countryService = countryService;
}
protected override bool TypesMatch(Type s, Type t)
{
return (s == typeof(string)) && (t == typeof (Country));
}
protected override Object SetValue(object v)
{
if (v == null)
return null;
var country = countryService.LookupCode((string) v);
return country;
}
public override string SourceName()
{
return "CountryCode";
}
public override string TargetName()
{
return "Country";
}
}
public Member InjectFromDto (MemberDto dto, Member source)
{
source = source.InjectFrom<UnflatLoopValueInjection>(dto)
.InjectFrom<CountryLookup>(dto);
return source;
}
Is a framework calling the setter method? In most DI frameworks, the standard is lowercase 's' in the setMethod(). Just a first-thought recommendation.
All of my entities and value objects implement marker interfaces IEntity and IValueObject. I have set them up to be treated as components like so:
public override bool IsComponent(Type type)
{
return typeof(IValueObject).IsAssignableFrom(type);
}
public override bool ShouldMap(Type type)
{
return typeof(IEntity).IsAssignableFrom(type) || typeof(IValueObject).IsAssignableFrom(type);
}
Unfortunately, this does not seem to allow entities that have collections of value objects to be automapped as component collections. For example:
public class MyEntity : IEntity
{
public IList<MyValueObject> Objects { get; set; }
}
public class MyValueObject : IValueObject
{
public string Name { get; set; }
public string Value { get; set; }
}
Is there any way to define a convention such that, any time an IEntity has an IList of a type that implements IValueObject, it gets mapped as if I had specified:
HasMany(x => x.Objects)
.Component(x => {
x.Map(m => m.Name);
x.Map(m => m.Value);
});
What I don't want to do is have to manually do these overrides for every class and write out each property for the value object again and again.
Create a new class that inherits from HasManyStep (FluentNHibernate.Automapping.Steps).
Override the ShouldMap() method with something like :
return base.ShouldMap(member) && IsCollectionOfComponents(member)
Add your logic to :
public void Map(ClassMappingBase classMap, Member member)
{ ... }
Replace the default step with your new one :
public class MyMappingConfiguration : DefaultAutomappingConfiguration
{
public override IEnumerable<IAutomappingStep> GetMappingSteps(AutoMapper mapper, IConventionFinder conventionFinder)
{
var steps = base.GetMappingSteps(mapper, conventionFinder);
var finalSteps = steps.Where(c => c.GetType() != typeof(FluentNHibernate.Automapping.Steps.HasManyToManyStep)).ToList();
var idx = finalSteps.IndexOf(steps.Where(c => c.GetType() == typeof(PropertyStep)).First());
finalSteps.Insert(idx + 1, new MyCustomHasManyStep(this));
return finalSteps;
}
}
Note : You could also get the original source code of HasManyStep.cs and copy it to your project to introduce your custom logic.
I have two tables, Locations and Facilities
They map to two classes,
public Location : Entity
{
//properties
}
public Facility : Entity
{
public virtual Location Location { get; set; }
}
Everything works just dandy, until I change facility to this
public Facility : Location
{
}
Now I get an exception from nHibernate saying
NHibernate.ADOException was unhandled by user code
Message=could not execute query
InnerException: System.Data.SqlClient.SqlException
Message=Invalid object name 'Facility'.
For some reason it is not creating the plural name of the table into the sql string.
Thanks for any help!
EDIT
This is my current TableNameConvention
public class TableNameConvention : IClassConvention
{
public void Apply(FluentNHibernate.Conventions.Instances.IClassInstance instance)
{
instance.Table(Inflector.Net.Inflector.Pluralize(instance.EntityType.Name));
}
}
When Facility inherits from Entity, the Facility does run through this method. When it inherits from Location, it does not
Edit 2
Figured I'd post everything...
public class AutoPersistenceModelGenerator : IAutoPersistenceModelGenerator
{
#region IAutoPersistenceModelGenerator Members
public AutoPersistenceModel Generate()
{
var mappings = new AutoPersistenceModel();
mappings.AddEntityAssembly(typeof(Person).Assembly).Where(GetAutoMappingFilter);
mappings.Conventions.Setup(GetConventions());
mappings.Setup(GetSetup());
mappings.IgnoreBase<Entity>();
mappings.IgnoreBase(typeof(EntityWithTypedId<>));
mappings.UseOverridesFromAssemblyOf<AutoPersistenceModelGenerator>();
return mappings;
}
#endregion
private Action<AutoMappingExpressions> GetSetup()
{
return c =>
{
c.FindIdentity = type => type.Name == "Id";
};
}
private Action<IConventionFinder> GetConventions()
{
return c =>
{
c.Add<BHP.DEC.Data.NHibernateMaps.Conventions.ForeignKeyConvention>();
c.Add<BHP.DEC.Data.NHibernateMaps.Conventions.HasManyConvention>();
c.Add<BHP.DEC.Data.NHibernateMaps.Conventions.HasManyToManyConvention>();
c.Add<BHP.DEC.Data.NHibernateMaps.Conventions.ManyToManyTableNameConvention>();
c.Add<BHP.DEC.Data.NHibernateMaps.Conventions.PrimaryKeyConvention>();
c.Add<BHP.DEC.Data.NHibernateMaps.Conventions.ReferenceConvention>();
c.Add<BHP.DEC.Data.NHibernateMaps.Conventions.TableNameConvention>();
};
}
/// <summary>
/// Provides a filter for only including types which inherit from the IEntityWithTypedId interface.
/// </summary>
private bool GetAutoMappingFilter(Type t)
{
return t.GetInterfaces().Any(x =>
x.IsGenericType &&
x.GetGenericTypeDefinition() == typeof(IEntityWithTypedId<>));
}
}
Have you set a convention?
public class TableNameConvention : IClassConvention
{
public void Apply(FluentNHibernate.Conventions.Instances.IClassInstance instance)
{
string typeName = instance.EntityType.Name;
instance.Table(Inflector.Net.Inflector.Pluralize(typeName));
}
}
This is an old question, but for the sake of others who stumble upon this looking for an answer, you can also create a convention that uses the built-in PluralizationService that comes with EF:
public class TableNameConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
string typeName = instance.EntityType.Name;
instance.Table(PluralizationService.CreateService(CultureInfo.CurrentCulture).Pluralize(typeName));
}
}
I'm trying to map int IdPost on DTO to Post object on Blog object, based on a rule.
I would like to achieve this: BlogDTO.IdPost => Blog.Post
Post would be loaded by NHibernate: Session.Load(IdPost)
How can I achieve this with AutoMapper?
You could define AfterMap action to load entities using NHibernate in your mapping definition. I'm using something like this for simmilar purpose:
mapperConfiguration.CreateMap<DealerDTO, Model.Entities.Dealer.Dealer>()
.AfterMap((src, dst) =>
{
if (src.DepartmentId > 0)
dst.Department = nhContext.CurrentSession.Load<CompanyDepartment>(src.DepartmentId);
if (src.RankId > 0)
dst.Rank = nhContext.CurrentSession.Load<DealerRank>(src.RankId);
if (src.RegionId > 0)
dst.Region = nhContext.CurrentSession.Load<Region>(src.RegionId);
});
you can do this easily with the ValueInjecter
it would be something like this:
//first you need to create a ValueInjection for your scenario
public class IntToPost : LoopValueInjection<int, Post>
{
protected override Post SetValue(int sourcePropertyValue)
{
return Session.Load(sourcePropertyValue);
}
}
// and use it like this
post.InjectFrom(new IntToPost().SourcePrefix("Id"), postDto);
also if you always have the prefix Id than you could set it in the constructor of the IntToPost
and use it like this:
post.InjectFrom<IntToPost>(postDto);
Create a new Id2EntityConverter
public class Id2EntityConverter<TEntity> : ITypeConverter<int, TEntity> where TEntity : EntityBase
{
public Id2EntityConverter()
{
Repository = ObjectFactory.GetInstance<Repository<TEntity>>();
}
private IRepository<TEntity> Repository { get; set; }
public TEntity ConvertToEntity(int id)
{
var toReturn = Repository.Get(id);
return toReturn;
}
#region Implementation of ITypeConverter<int,TEntity>
public TEntity Convert(ResolutionContext context)
{
return ConvertToEntity((int)context.SourceValue);
}
#endregion
}
Configure AM to auto create maps for each type
public class AutoMapperGlobalConfiguration : IGlobalConfiguration
{
private AutoMapper.IConfiguration _configuration;
public AutoMapperGlobalConfiguration(IConfiguration configuration)
{
_configuration = configuration;
}
public void Configure()
{
//add all defined profiles
var query = this.GetType().Assembly.GetExportedTypes()
.Where(x => x.CanBeCastTo(typeof(AutoMapper.Profile)));
_configuration.RecognizePostfixes("Id");
foreach (Type type in query)
{
_configuration.AddProfile(ObjectFactory.GetInstance(type).As<Profile>());
}
//create maps for all Id2Entity converters
MapAllEntities(_configuration);
Mapper.AssertConfigurationIsValid();
}
private static void MapAllEntities(IProfileExpression configuration)
{
//get all types from the my assembly and create maps that
//convert int -> instance of the type using Id2EntityConverter
var openType = typeof(Id2EntityConverter<>);
var idType = typeof(int);
var persistentEntties = typeof(MYTYPE_FROM_MY_ASSEMBLY).Assembly.GetTypes()
.Where(t => typeof(EntityBase).IsAssignableFrom(t))
.Select(t => new
{
EntityType = t,
ConverterType = openType.MakeGenericType(t)
});
foreach (var e in persistentEntties)
{
var map = configuration.CreateMap(idType, e.EntityType);
map.ConvertUsing(e.ConverterType);
}
}
}
Pay attention to MapAllEntities method. That one will scan all types and create maps on the fly from integer to any type that is of EntityBase (which in our case is any persistent type).
RecognizePostfix("Id") in your case might be replace with RecognizePrefix("Id")