6

タイトルが意味をなすかどうかはわかりませんが、これが私がやっていることです。AutoMapper を使用して、Entity Framework エンティティを DTO オブジェクトに、またはその逆にマップしています。問題は、DTO データを EF エンティティにマップしようとしたときに発生します。EntityKey のプロパティ間のマッピングはありません。これを修正するために、次のようなことを行います。

        Mapper.CreateMap<VideoDTO, Video>()
            .ForMember(dest => dest.EntityKey, opt =>   
opt.ResolveUsing<VideoEntityKeyResolver>());

VideoEntityKeyResolver クラスは次のようになります。

public class VideoEntityKeyResolver : ValueResolver<VideoDTO, EntityKey>
{
    protected override EntityKey ResolveCore(VideoDTO source)
    {
        EntityKey key = new EntityKey("EntityFrameworkTestingEntities.Videos",
            "VideoId", source.VideoId);
        return key;
    }
}

コンストラクターでエンティティ セット名、キー プロパティ名、およびキー値を取るコンストラクターを持つ 1 つのクラスを持つことができる、これを行うためのより一般的な方法があるかどうか疑問に思っていました。

DTO オブジェクトを作成する全体的なポイントは、アプリケーションの残りのデータ層との結びつきを断ち切ることだったので、ストリームを横断するように聞こえる EntityKey プロパティを DTO オブジェクトに追加することだけを考えました。

まったく関係のないことですが (必要に応じて新しい質問を作成できます)、AutoMapper を使用する場合、どこでマッピングを定義する必要がありますか? 現在、私はコンテキスト オブジェクト (私の EF リポジトリ オブジェクト) のコンストラクターでそれを行っていますが、それはかなりコストがかかり、正しくないと思いますが、機能します。

4

1 に答える 1

8

これをテストするまでには行っていませんが、次のように動作するはずです。

public class EntityKeyResolver<T, TProperty> : ValueResolver<T, EntityKey> where T : class
{
    private Expression<Func<T, TProperty>> _propertyExpression;
    private string _qualifiedEntitySetName;
    private string _keyName;

    public EntityKeyResolver(string qualifiedEntitySetName, string keyName, Expression<Func<T, TProperty>> propertyExpression)
    {
        _qualifiedEntitySetName = qualifiedEntitySetName;
        _keyName = keyName;
        _propertyExpression = propertyExpression;
    }

    protected override EntityKey ResolveCore(T source)
    {
        return new EntityKey(_qualifiedEntitySetName, _keyName, ExpressionHelper.GetValue(_propertyExpression));
    }
}

ExpressionHelper、さまざまなケースで式を評価するために使用する静的クラスです。GetValue メソッドは次のようになります。

internal static TProperty GetValue<T, TProperty>(T obj, Expression<Func<T, TProperty>> expression) where T : class
{
    if (obj == null)
    {
        return default(TProperty);
    }

    Func<T, TProperty> func = expression.Compile();

    return func(obj);
}

次に、コードを次のように変更します (VideoId が Guid であると仮定します)。

Mapper.CreateMap<VideoDTO, Video>()         
            .ForMember(dest => dest.EntityKey, opt => opt.ResolveUsing(new EntityKeyResolver<VideoDTO, Guid>("EntityFrameworkTestingEntities.Videos", "VideoId", v => v.VideoId)));

おそらく、あなたが望んでいたよりも少し冗長です。一般的なリゾルバーの代わりに、MapFrom を使用してエンティティ キーをマップすることもできます (それらはほぼ同じくらい冗長です)。

Mapper.CreateMap<VideoDTO, Video>()         
                .ForMember(dest => dest.EntityKey, opt => opt.MapFrom(src => new EntityKey("EntityFrameworkTestingEntities.Videos", "VideoId", src.VideoId)));

他の質問については、AppDomain ごとに 1 回呼び出すだけでよいため、マップを初期化し、マッピングが作成されたかどうかを示すブール値を設定する静的クラスを作成する習慣を身につけました。次に、リポジトリのコンストラクターで、単に呼び出しますMapInitializer.EnsureMaps();

于 2010-01-28T03:55:10.323 に答える