[英]Converting a DTO's entityID to a Domain's entity through NHibernate and AutoMapper
我一直在阅读有关使用NHibernate和AutoMapper将DTO的entityID转换为Domain的实体的StackOverflow帖子。 其中肯定有很多信息,但每个人似乎都有不同的建议,其中许多建议完全使用不同的工具( ValueInjecter )。 此外,我发现的很多信息已经过了好几年了。 因此,我正在再次解决这个问题,希望为我解决问题。
我有以下DTO课程:
public class PlaylistDto
{
public Guid Id { get; set;
public Guid StreamId { get; set; }
public List<PlaylistItemDto> Items { get; set; }
}
和相应的域名:
public class Playlist
{
public Guid Id { get; set;
public Stream Stream { get; set; }
// Use interfaces so NHibernate can inject with its own collection implementation.
public IList<PlaylistItem> Items { get; set; }
}
首先,我声明我打算将这两个实体相互映射:
Mapper.CreateMap<Playlist, PlaylistDto>().ReverseMap();
Mapper.CreateMap<PlaylistItem, PlaylistItemDto>().ReverseMap();
Mapper.CreateMap<Stream, StreamDto>().ReverseMap();
ReverseMap允许我轻松声明双向映射。
此时,我可以毫不费力地将播放列表成功转换为PlaylistDto:
// Singular:
PlaylistDto playlistDto = Mapper.Map<Playlist, PlaylistDto>(playlist);
// Collection:
List<PlaylistDto> playlistDtos = Mapper.Map<List<Playlist>, List<PlaylistDto>>(playlists);
这非常有效。 不需要额外的代码。 但是,当我尝试映射另一个方向时会出现问题。
播放列表Dto仅存储其Stream的ID引用。 如果我将DTO转换为域,如下所示:
Playlist playlist = Mapper.Map<PlaylistDto, Playlist>(playlistDto);
无论playlistDto的StreamID如何,播放列表的Stream始终为null。
我想添加一个中间步骤,允许使用Dto的entityId通过NHibernate获取Domain的实体。
我没有使用AutoMapper,我会通过以下方式实现:
playlist.Stream = StreamDao.Get(playlistDto.StreamId);
话虽如此,我有疑问:
我看到的几个可能解决我的问题的例子:
Mapper.CreateMap<Person, Domain.Person>()
.ForMember(dest => dest.Address, opt => opt.ResolveUsing( src => { return new Address() {Address1 = src.Address, City = src.City, State = src.State }; }))
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
}
(there's more to this, but this is the gist of it)
建议表示赞赏。 谢谢!
Id2Entity转换器是我们在一个非常大的项目中广泛使用的,它可以完美地工作。 这里的诀窍是你扫描所有实体并设置从int到你的类型的映射。 如果您需要完整的代码,请告诉我。
这是创建映射的类。
public class AutoMapperGlobalConfiguration : IGlobalConfiguration
{
private readonly IConfiguration _configuration;
public AutoMapperGlobalConfiguration(IConfiguration configuration)
{
_configuration = configuration;
}
private void RegisterAssembly(Assembly assembly)
{
//add all defined profiles
var query = assembly.GetExportedTypes()
.Where(x => x.CanBeCastTo(typeof(Profile)));
foreach (Type type in query)
{
var profile = ObjectFactory.GetInstance(type).As<Profile>();
_configuration.AddProfile(profile);
Mapper.AddProfile(profile);
}
}
public void Configure()
{
_configuration.RecognizePostfixes("Id");
var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => a.FullName.StartsWith("DM."));
//create maps for all Id2Entity converters
MapAllEntities(_configuration);
assemblies.Each(RegisterAssembly);
}
private static void MapAllEntities(IProfileExpression configuration)
{
//get all types from the domain assembly and create maps that
//convert int -> instance of the type using Id2EntityConverter
var openType = typeof(Id2EntityConverter<>);
var idType = typeof(int);
var persistentEntties = typeof(Domain.Entities).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);
}
}
}
这是我目前的解决方案。 我认为我比Id2Entity转换器更喜欢这个,因为这似乎更容易调试/不那么聪明。 有时候不那么聪明,但更多的可调试性是关键。
如果有人知道如何简单地做到这一点,而不是手动,我很乐意听到它。
不要使用AfterMap()因为那样你就不能在不忽略很多属性的情况下调用AssertConfigurationIsValid()。 最好只调用ForMemeber。
/// <summary>
/// Initialize the AutoMapper mappings for the solution.
/// http://automapper.codeplex.com/
/// </summary>
private static void CreateAutoMapperMaps()
{
AutofacRegistrations.RegisterDaoFactory();
ILifetimeScope scope = AutofacRegistrations.Container.BeginLifetimeScope();
var daoFactory = scope.Resolve<IDaoFactory>();
Mapper.CreateMap<Error, ErrorDto>()
.ReverseMap();
IPlaylistItemDao playlistItemDao = daoFactory.GetPlaylistItemDao();
IPlaylistDao playlistDao = daoFactory.GetPlaylistDao();
IStreamDao streamDao = daoFactory.GetStreamDao();
IUserDao userDao = daoFactory.GetUserDao();
Mapper.CreateMap<Playlist, PlaylistDto>()
.ReverseMap()
.ForMember(playlist => playlist.FirstItem,
opt => opt.MapFrom(playlistDto => playlistItemDao.Get(playlistDto.FirstItemId)))
.ForMember(playlist => playlist.NextPlaylist,
opt => opt.MapFrom(playlistDto => playlistDao.Get(playlistDto.NextPlaylistId)))
.ForMember(playlist => playlist.PreviousPlaylist,
opt => opt.MapFrom(playlistDto => playlistDao.Get(playlistDto.PreviousPlaylistId)))
.ForMember(playlist => playlist.Stream,
opt => opt.MapFrom(playlistDto => streamDao.Get(playlistDto.StreamId)));
Mapper.CreateMap<PlaylistItem, PlaylistItemDto>()
.ReverseMap()
.ForMember(playlistItem => playlistItem.NextItem,
opt => opt.MapFrom(playlistItemDto => playlistItemDao.Get(playlistItemDto.NextItemId)))
.ForMember(playlistItem => playlistItem.PreviousItem,
opt => opt.MapFrom(playlistItemDto => playlistItemDao.Get(playlistItemDto.PreviousItemId)))
.ForMember(playlistItem => playlistItem.Playlist,
opt => opt.MapFrom(playlistItemDto => playlistDao.Get(playlistItemDto.PlaylistId)));
Mapper.CreateMap<ShareCode, ShareCodeDto>().ReverseMap();
Mapper.CreateMap<Stream, StreamDto>()
.ReverseMap()
.ForMember(stream => stream.User,
opt => opt.MapFrom(streamDto => userDao.Get(streamDto.UserId)))
.ForMember(stream => stream.FirstPlaylist,
opt => opt.MapFrom(streamDto => playlistDao.Get(streamDto.FirstPlaylistId)));
Mapper.CreateMap<User, UserDto>().ReverseMap();
Mapper.CreateMap<Video, VideoDto>().ReverseMap();
Mapper.AssertConfigurationIsValid();
}
您缺少(应用程序)服务层(客户端/表示层调用的服务层)。
该层接收请求(例如通过电子邮件获取)。
然后,它从域服务中获取域模型/实体并将其转换为DTO; 使用DTO提供者并在响应消息中将其发送回客户端,并将DTO作为内容的一部分。
同一层在另一个请求中接收dto(例如保存),它使用一个或多个域服务重建域模型/实体,验证要保留的模型,如果有效,则使用其对应的域保存域模型服务并返回响应,结果是成功,也许是新的ID; 否则,如果无效则返回验证结果失败。 (返回dto是可选的......)
查看此链接中的图层: http : //msdn.microsoft.com/en-us/library/ee658109.aspx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.