问题描述
免责声明:这是一个旧的 stackoverflow 帖子的复制粘贴,不再可用,但我遇到了同样的问题,因此似乎适合重新发布它,因为它从未得到答复.
我有一个存储过程,它将返回 4 个结果集(联系人、地址、电子邮件、电话),这些结果集被填充到数据集中.我想使用 AutoMapper 来填充一个复杂的对象.
I have a stored procedure that will return 4 result sets (contacts, addresses, email, phones) which is populated into a dataset. I would like to use AutoMapper to populate a complex object.
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 后,我定义表之间的关系.
I have a method that will get data and return a list of contact. After the DataSet is populate, I define the relationships between the tables.
我发现了许多使用 CreateDataReader 方法将 DataSet(或表)转换为读取器的示例,这就是我在这里所做的.该方法实际上会将第一个表解析为对象,但不会枚举相关表.
I found many examples where you convert the DataSet (or table) to a reader using the CreateDataReader method and that is what I'm doing here. The method will in fact parse the first table into the object, but will not enumerate through the related tables.
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 对象的映射中遗漏了一些东西,但我就是找不到一个好的例子来效仿.
I feel as though I'm missing something in the mapping for the Contact object, but I just can't find a good example to follow.
如果我手动填充联系人对象,然后将其传递给我的控制器,它将使用直接映射正确加载 ContactModel 对象
If I manually populate the contact object and then pass is to my controller, it will properly load the ContactModel object using a direct mapping
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);
}
我想做的事是否可能?
推荐答案
IDataReader 映射器是一个非常简单的映射器,它可以从数据读取器中填充一个对象,其中它通过列名映射对象属性.它并非旨在创建具有关系等的复杂数据结构.
IDataReader mapper is very simple one, it can populate an object out of a data reader, where it maps the object properties by column names. It was not designed to create a complex data structures with relations, etc.
此外,DataSet.CreateDataReader 将生成一个多结果集数据读取器 - 即,读取器对于每个表的结果集很少,但它不会保留关系.
Also, the DataSet.CreateDataReader will produce a multiple resultset data reader - i.e. the reader will have few result sets for each table, but it will not preserve the relations.
所以,为了得到你想要的,你需要为每个表创建阅读器,将每个阅读器映射到不同的集合,然后使用这些结果来创建最终的复杂对象.
So, in order to get what you want, you need to create reader for each table, map each reader to different collection, and then use these results to create the final complex object(s).
我在这里提供了一种简单的方法,但您可以尽情发挥,创建自定义解析器等,封装一切.
Here I'm providing the simplistic approach, but you can go wild, and create custom resolvers, etc., to encapsulate everything.
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();
}
}
}
}
这篇关于如何使用 automapper 映射具有多个表的数据集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!