2013-05-28 61 views
6

免責聲明:這是從舊的stackoverflow帖子複製粘貼不再可用,但我已經exaclty相同的問題,所以它似乎適當重新發布它因爲它從來沒有回答過。如何使用自動映射器映射一個數據集與多個表

我有一個存儲過程,將返回填充到數據集中的4個結果集(聯繫人,地址,電子郵件,電話)。我想使用AutoMapper來填充複雜的對象。

public class Contact 
{ 
    public Guid ContactId { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public List<Address> Addresses { get; set; } 
    public List<Phone> Phones { get; set; } 
    public List<Email> Emails { get; set; } 
} 

public partial class Address:BaseClass 
{ 
    public Guid ContactId { get; set; } 
    public string Address1 { get; set; } 
    public string Address2 { get; set; } 
    public string Address3 { get; set; } 
    public string City { get; set; } 
    public string StateProvince { get; set; } 
    public string PostalCode { get; set; } 
    public string CountryCode { get; set; } 
} 

public class Email 
{ 
    public Guid EmailId { get; set; } 
    public Guid ContactId { get; set; } 
    public string EmailAddress { get; set; } 
} 

public class Phone 
{ 
    public Guid PhoneId { get; set; } 
    public Guid ContactId { get; set; }   
    public string Number { get; set; } 
    public string Extension { get; set; } 
} 

我有一個方法,將獲得數據並返回聯繫人列表。 DataSet填充後,我定義了表之間的關係。

我發現了許多使用CreateDataReader方法將DataSet(或表)轉換爲reader的示例,這就是我在這裏做的。該方法實際上將第一個表解析爲對象,但不會通過相關表進行枚舉。

public List<Contact> GetContacts() 
{ 
    List<Contact> theList = null; 

    // Get the data 
    Database _db = DatabaseFactory.CreateDatabase(); 
    DataSet ds = db.ExecuteDataSet(CommandType.StoredProcedure, "GetContacts"); 

    //The dataset should contain 4 tables 
    if (ds.Tables.Count == 4) 
    {  
     //Create the maps 
     Mapper.CreateMap<IDataReader, Contact>(); // I think I'm missing something here 
     Mapper.CreateMap<IDataReader, Address>(); 
     Mapper.CreateMap<IDataReader, Email>(); 
     Mapper.CreateMap<IDataReader, Phone>(); 

     //Define the relationships   
     ds.Relations.Add("ContactAddresses", ds.Tables[0].Columns["ContactId"], ds.Tables[1].Columns["ContactId"]); 
     ds.Relations.Add("ContactEmails", ds.Tables[0].Columns["ContactId"], ds.Tables[2].Columns["ContactId"]); 
     ds.Relations.Add("ContactPhones", ds.Tables[0].Columns["ContactId"], ds.Tables[3].Columns["ContactId"]); 

     IDataReader dr = ds.CreateDataReader(); 
     theList = Mapper.Map<List<Contact>>(dr);  
    } 

    return (theList);  
} 

我覺得好像我錯過在聯繫對象的映射的東西,但我不能找到一個很好的榜樣。

如果我手動填充接觸對象,然後傳遞是我的控制器,它能夠正常使用直接映射

public ActionResult Index() 
{ 
    //From the ContactController 
    Mapper.CreateMap<Contact, Models.ContactModel>(); 
    Mapper.CreateMap<Address, Models.AddressModel>(); 

    List<Models.ContactModel> theList = Mapper.Map<List<Contact>, List<Models.ContactModel>>(contacts); 

    return View(theList); 
} 

就是我想要做的甚至有可能加載ContactModel對象?

回答

9

IDataReader映射器非常簡單,它可以將數據讀取器中的對象填充到數據讀取器中,其中按列名映射對象屬性。它不是用來創建與關係的複雜數據結構等。

此外,DataSet.CreateDataReader將生成多結果集數據讀取器 - 即讀取器對每個表都有幾個結果集,但它不會保留關係。

因此,爲了得到您想要的,您需要爲每個表創建讀取器,將每個讀取器映射到不同的集合,然後使用這些結果創建最終的複雜對象。

在這裏,我提供了簡單的方法,但你可以去野外,並且可以封裝所有東西。

using System; 
using System.Collections.Generic; 
using System.Data; 
using System.Linq; 
using AutoMapper; 
using NUnit.Framework; 

namespace StackOverflowExample.Automapper 
{ 
    public class Contact 
    { 
     public Guid ContactId { get; set; } 
     public string Name { get; set; } 
     public List<Address> Addresses { get; set; } 
    } 

    public partial class Address 
    { 
     public Guid AddressId { get; set; } 
     public Guid ContactId { get; set; } 
     public string StreetAddress { get; set; } 
    } 

    [TestFixture] 
    public class DatasetRelations 
    { 
     [Test] 
     public void RelationMappingTest() 
     { 
      //arrange 
      var firstContactGuid = Guid.NewGuid(); 
      var secondContactGuid = Guid.NewGuid(); 

      var addressTable = new DataTable("Addresses"); 
      addressTable.Columns.Add("AddressId"); 
      addressTable.Columns.Add("ContactId"); 
      addressTable.Columns.Add("StreetAddress"); 
      addressTable.Rows.Add(Guid.NewGuid(), firstContactGuid, "c1 a1"); 
      addressTable.Rows.Add(Guid.NewGuid(), firstContactGuid, "c1 a2"); 
      addressTable.Rows.Add(Guid.NewGuid(), secondContactGuid, "c2 a1"); 

      var contactTable = new DataTable("Contacts"); 
      contactTable.Columns.Add("ContactId"); 
      contactTable.Columns.Add("Name"); 
      contactTable.Rows.Add(firstContactGuid, "contact1"); 
      contactTable.Rows.Add(secondContactGuid, "contact2"); 

      var dataSet = new DataSet(); 
      dataSet.Tables.Add(contactTable); 
      dataSet.Tables.Add(addressTable); 

      Mapper.CreateMap<IDataReader, Address>(); 
      Mapper.CreateMap<IDataReader, Contact>().ForMember(c=>c.Addresses, opt=>opt.Ignore()); 

      //act 
      var addresses = GetDataFromDataTable<Address>(dataSet, "Addresses"); 
      var contacts = GetDataFromDataTable<Contact>(dataSet, "Contacts"); 
      foreach (var contact in contacts) 
      { 
       contact.Addresses = addresses.Where(a => a.ContactId == contact.ContactId).ToList(); 
      } 
     } 

     private IList<T> GetDataFromDataTable<T>(DataSet dataSet, string tableName) 
     { 
      var table = dataSet.Tables[tableName]; 
      using (var reader = dataSet.CreateDataReader(table)) 
      { 
       return Mapper.Map<IList<T>>(reader).ToList(); 
      } 
     } 
    } 
} 
+1

我擔心這將是答案,謝謝你的例子! –

0

我對晚會非常遲到,但如果這有助於其他人。

我所做的是使用Json.NET將我的數據集序列化爲JSON字符串。

var datasetSerialized = JsonConvert.SerializeObject(dataset, Formatting.Indented); 

在Visual Studio中調試時將json視爲字符串並將其複製到剪貼板。

然後在Visual Studio中去編輯 - >選擇性粘貼 - >粘貼JSON作爲類

然後,您將有一個POCO與關係每個表。

最後,將JSON反序列化爲粘貼JSON As Classes時創建的「RootObject」。

var rootObj = JsonConvert.DeserializeObject<RootObject>(datasetSerialized);