コレクションのエミットマッパーのリストマッピングの問題
-
27-10-2019 - |
質問
ソースクラス:
public class Post
{
public long ID { get; set; }
[Column(TypeName="nvarchar")]
[Required]
[StringLength(250)]
public string Name { get; set; }
[Column(TypeName="varchar")]
[StringLength(250)]
public string UrlName { get; set; }
[Column(TypeName="ntext")]
public string Excerpt { get; set; }
[Column(TypeName="ntext")]
[Required]
public string Content { get; set; }
public DateTime PostedTime { get; set; }
public DateTime? PublishedTime { get; set; }
public DateTime? LastUpdatedTime { get; set; }
public bool IsPublished { get; set; }
public virtual List<Category> Categories { get; set; }
public virtual List<Comment> Comments { get; set; }
public virtual List<Tag> Tags { get; set; }
}
宛先クラス
public class Post : Model
{
public long ID { get; set; }
public string Name { get; set; }
public string UrlName { get; set; }
public string Excerpt { get; set; }
public string Content { get; set; }
public DateTime PostedTime { get; set; }
public DateTime LastCommentedTime { get; set; }
public bool IsPublished { get; set; }
public List<Category> Category { get; set; }
public List<Comment> Comments { get; set; }
public List<Tag> Tags { get; set; }
}
EmitMapperを使用してお互いからマッピングしてみます。ソースからデスクションへのマッピングの場合、コードサンプルを次に示します。
[TestMethod]
public void ShouleMapEntityToModel()
{
Post eP = new Post();
eP.ID = 2;
eP.Comments = new List<Comment>();
eP.Comments.Add(new Comment()
{
ID = 2,
Author = "derek"
});
var mP = eP.Map<Post, mBlog.Core.Models.Post>();
Assert.IsNotNull(mP);
Assert.AreEqual(1, mP.Comments.Count());
}
そして、私は例外を得ました、
テスト方法mblog.test.emitmappertest.shoulemapentitytomodelは例外を投げました:system.exception:system.collections.generic.ilist`1 [] in constructions.generic.ilist`1 [[mblog.core.models.post、mblog.core、version = 1.0.0.0 .0.0、culture = neutral、publickeytoken = null]
解決
私は同じ問題を抱えていましたが、解決策を見つけました。宛先オブジェクトのユーザーリストはありません。 mblog.core.models.postオブジェクトで単純な配列を使用する場合、きれいに満たされたオブジェクトを取得する必要があります。したがって、目的地のクラスは次のように見えます。
public class Post : Model
{
public long ID { get; set; }
public string Name { get; set; }
public string UrlName { get; set; }
public string Excerpt { get; set; }
public string Content { get; set; }
public DateTime PostedTime { get; set; }
public DateTime LastCommentedTime { get; set; }
public bool IsPublished { get; set; }
public Category[] Category { get; set; }
public Comment[] Comments { get; set; }
public Tag[] Tags { get; set; }
}
他のヒント
この回答は、IENUMERABLEからIENUMERABLEを処理する方法を示しています。 エミットマッパーとリスト
この場合にも適用できると思います。見てください:
これは、カスタムクラスを作成し、インターフェイス「icustomConverterProvider」を実装し、convertGenericを「defaultMapConfig」に追加することができます。
EmitMapperのソースコードを見ると、「ArraysConverterProvider」という名前のクラスが見つかりました。これは、IcollectionsからArraysまでのデフォルトの一般的なコンバーターです。
このクラスのコードをIENUMERABLEコレクションで操作するために採用します。
class GenericIEnumerableConverterProvider : ICustomConverterProvider { public CustomConverterDescriptor GetCustomConverterDescr( Type from, Type to, MapConfigBaseImpl mappingConfig) { var tFromTypeArgs = DefaultCustomConverterProvider.GetGenericArguments(from); var tToTypeArgs = DefaultCustomConverterProvider.GetGenericArguments(to); if (tFromTypeArgs == null || tToTypeArgs == null || tFromTypeArgs.Length != 1 || tToTypeArgs.Length != 1) { return null; } var tFrom = tFromTypeArgs[0]; var tTo = tToTypeArgs[0]; if (tFrom == tTo && (tFrom.IsValueType || mappingConfig.GetRootMappingOperation(tFrom, tTo).ShallowCopy)) { return new CustomConverterDescriptor { ConversionMethodName = "Convert", ConverterImplementation = typeof(GenericIEnumerableConverter_OneTypes<>), ConverterClassTypeArguments = new[] { tFrom } }; } return new CustomConverterDescriptor { ConversionMethodName = "Convert", ConverterImplementation = typeof(GenericIEnumerableConverter_DifferentTypes<,>), ConverterClassTypeArguments = new[] { tFrom, tTo } }; } } class GenericIEnumerableConverter_DifferentTypes<TFrom, TTo> : ICustomConverter { private Func<TFrom, TTo> _converter; public IEnumerable<TTo> Convert(IEnumerable<TFrom> from, object state) { if (from == null) { return null; } TTo[] result = new TTo[from.Count()]; int idx = 0; foreach (var f in from) { result[idx++] = _converter(f); } return result; } public void Initialize(Type from, Type to, MapConfigBaseImpl mappingConfig) { var staticConverters = mappingConfig.GetStaticConvertersManager() ?? StaticConvertersManager.DefaultInstance; var staticConverterMethod = staticConverters.GetStaticConverter(typeof(TFrom), typeof(TTo)); if (staticConverterMethod != null) { _converter = (Func<TFrom, TTo>)Delegate.CreateDelegate( typeof(Func<TFrom, TTo>), null, staticConverterMethod ); } else { _subMapper = ObjectMapperManager.DefaultInstance.GetMapperImpl(typeof(TFrom), typeof(TTo), mappingConfig); _converter = ConverterBySubmapper; } } ObjectsMapperBaseImpl _subMapper; private TTo ConverterBySubmapper(TFrom from) { return (TTo)_subMapper.Map(from); } } class GenericIEnumerableConverter_OneTypes<T> { public IEnumerable<T> Convert(IEnumerable<T> from, object state) { if (from == null) { return null; } return from; } }
このコードは、可能な限り最小限の適応を伴うコピーであり、多くのレベルの階層を持つオブジェクトに適用できます。
次のコマンドで上記のコードを使用できます。
new DefaultMapConfig().ConvertGeneric( typeof(IEnumerable<>), typeof(IEnumerable<>), new GenericIEnumerableConverterProvider());
これは私の一日を救ったので、私もあなたの日を救うことを望んでいます! hehehe