免责声明:这是旧版stackoverflow帖子中的一个副本粘贴,不再可用,但我有同样的问题,所以重新发布它似乎是合适的,因为它从未被回答。
我有一个存储过程,它将返回填充到数据集中的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(或表)转换为阅读器的示例,这就是我在这里所做的。该方法实际上将第一个表解析为对象,但不会枚举相关表。
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);
}
我觉得好像我在Contact对象的映射中遗漏了一些东西,但我找不到一个好的例子。
如果我手动填充联系人对象然后传递给我的控制器,它将使用直接映射正确加载ContactModel对象
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);
}
我想做什么甚至可能?
答案 0 :(得分:9)
IDataReader映射器非常简单,它可以从数据读取器中填充对象,它可以按列名映射对象属性。它不是为了创建具有关系等的复杂数据结构而设计的。
此外,DataSet.CreateDataReader将生成一个多结果集数据读取器 - 即读者将为每个表提供很少的结果集,但它不会保留关系。
因此,为了得到你想要的东西,你需要为每个表创建阅读器,将每个阅读器映射到不同的集合,然后使用这些结果来创建最终的复杂对象。
在这里,我提供了简单的方法,但你可以疯狂,create custom resolvers等等,以封装一切。
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中转到编辑 - &gt;选择性粘贴 - &gt;将JSON粘贴为类
然后,您将为每个具有关系的表格提供POCO。
最后,将JSON反序列化为粘贴JSON As Classes时创建的“RootObject”。
var rootObj = JsonConvert.DeserializeObject<RootObject>(datasetSerialized);