1

文字列型フィールド内に XML データのブロックを格納するデータベース テーブルがあります。その XML の特定の要素をカスタム ViewModel に抽出したいと考えています。

この例では、ErrorTableModel.ErrorXML がサンプルの XML 文字列を保持しています。その文字列から「メッセージ」要素を取得して、ErrorViewModel.message にマップしようとしています。

AutoMapper を使用してこれを達成することは可能でしょうか?

サンプル文字列。このデータは、ErrorTableModel の ErrorXML プロパティに格納されます。

<error
  application="TestApp"
  type="System.DivideByZeroException"
  message="Something wicked this way comes."
</error>

データベース モデル:

public class ErrorTableModel
{
    public int ErrorId { get; set; }
    public string ErrorXml { get; set; }
}

カスタム ビューモデル:

public class ErrorViewModel
{
    public int id { get; set; }
    public string application { get; set; }
    public string type { get; set; }
    public string message { get; set; }
}

更新: XML の分割を支援するための新しいヘルパー クラスを作成しました。

protected override T ResolveCore(XElement source)
{
    if (source == null || string.IsNullOrEmpty(source.Value))
    {
        return default(T);
    }

    return (T)Convert.ChangeType(source.Value, typeof(T));
}

ErrorViewModel からマッピングを実行するときに、そのメソッドを参照しようとしています。

    Mapper.CreateMap<XElement, ErrorViewModel>()
        .ForMember(
            dest => dest.ErrorXml,
            options => options.ResolveUsing<XElementResolver<string>>()
                .FromMember(source => source.Element("error")
                .Descendants("message").Single()));

悲しいことに、これは機能しません...しかし、私は近いと思います。

更新 2:

明確にするために、結果のデータを次のようにしたいと思います。

  ErrorViewModel.application = "TestApp"
  ErrorViewModel.type = "System.DivideByZeroException"
  ErrorViewModel.message = "Something wicked this way comes."
4

1 に答える 1

4

このようなもの:

public class ErrorConverter1 : ITypeConverter<ErrorTableModel, ErrorViewModel>
{
    public ErrorViewModel Convert(ResolutionContext context)
    {
        var dbModel = context.SourceValue as ErrorTableModel;

        if (dbModel == null) 
            return null;

        var xDocument = XDocument.Parse(dbModel.ErrorXml);

        var errorElement = xDocument.Descendants(XName.Get("error")).Single();

        return new ErrorViewModel()
        {
            id = dbModel.ErrorId,
            application = errorElement.Attribute(XName.Get("application")).Value,
            type =  errorElement.Attribute(XName.Get("type")).Value,
            message = errorElement.Attribute(XName.Get("message")).Value
        };
    }
}

または XML デシリアライゼーションを介して。このためには、ErrorViewModelクラスを次のように変更する必要があります。

[XmlRoot("error")]
public class ErrorViewModel
{
    public int id { get; set; }

    [XmlAttribute("application")]
    public string application { get; set; }

    [XmlAttribute("type")]
    public string type { get; set; }

    [XmlAttribute("message")]
    public string message { get; set; }
}

public class ErrorConverter2 : ITypeConverter<ErrorTableModel, ErrorViewModel>
{
    public ErrorViewModel Convert(ResolutionContext context)
    {
        var dbModel = context.SourceValue as ErrorTableModel;

        if (dbModel == null)
            return null;

        var serializer = new XmlSerializer(typeof(ErrorViewModel));

        var result = (ErrorViewModel) serializer.Deserialize(new StringReader(dbModel.ErrorXml));

        result.id = dbModel.ErrorId;

        return result;
    }
}

使い方はこんな感じです。

public class MappingProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<ErrorTableModel, ErrorViewModel>()
            .ConvertUsing<ErrorConverter1>()//or use the ErrorConverter2
            ;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Mapper.Initialize(x => x.AddProfile<MappingProfile>());

        var dbModel = new ErrorTableModel()
        {
            ErrorId = 1,
            ErrorXml =
                "<error application=\"TestApp\" type=\"System.DivideByZeroException\" message=\"Something wicked this way comes.\"></error>"
        };

        var viewModel = Mapper.Map<ErrorTableModel, ErrorViewModel>(dbModel);

        Console.WriteLine(viewModel.id);
        Console.WriteLine(viewModel.application);            
        Console.WriteLine(viewModel.type);
        Console.WriteLine(viewModel.message);

    }
}

必要に応じてガード句を追加します。

于 2013-11-01T15:44:00.823 に答える