繁体   English   中英

存储过程返回复杂类型,我使用 AutoMapper 将其映射到我的模型,但未设置外键对象

[英]Stored procedure returns complex type, I use AutoMapper to map it to my model but foreign key objects do not get set

我使用 AutoMapper 从我的 DataLayer(EF6 DbFirst AutoGenerated 层)映射到我的 ModelLayer(Pocos/Dtos)。 我感到困惑的一件事是,当使用存储过程时,它们会返回一个复杂的对象,例如 Customer_GetCustomers_Result,因此我必须使用 AutoMapper 将其映射到我的 CustomerPoco 并且丢失了诸如 Customer.Address 的外键对象属性,因为它们不在我的复杂类型中.

这是我的 CustomerPoco 的示例:

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Phone { get; set; }
    public string Fax { get; set; }
    public string Website { get; set; }
    public int AddressId { get; set; }

    // THESE END UP NOT GETTING SET
    public List<CustomerContact> Contacts { get; set; }
    public Address Address { get; set; }
}

在我的 GetCustomers 存储过程中,可以说我做了一些简单的事情:SELECT * FROM CUSTOMER。 它返回一个复杂的对象 context.Customer_GetCustomers_Result。 然后我必须将这个复杂的对象映射到我的 CustomerPoco。 联系人和地址未设置。 我应该怎么做?

这是我对客户的映射:

    CreateMap<Customer, Model.Customer>()
        .ForMember(dest => dest.Contacts, opt => opt.MapFrom(src => src.CustomerContacts));

    CreateMap<Customer_GetCustomers_Result, Model.Customer>();

这实际上可能是一个糟糕的问题。 我相信如果我真的想使用存储过程来返回我的列表,我将需要进行连接并在我的选择中实际返回 Address 的属性,例如... a.Address1、a.Address2 等。 那么有没有办法从这里将它们映射到 Model.Customer.Address 即使它们都被拆分为单独的属性?

我认为您在这里有两个单独的问题需要解决。 第一个是如何让存储过程返回并将所有数据绑定到您的 EF 复杂类型。 这里(博客)这里(CodeProject)有几篇文章应该会有所帮助。 本质上,编写 sproc 以返回多个结果集,并编写几行代码以前进到下一个结果集并将其读入上下文。

要从 AutoMapper 获得所需的映射,您还需要为用作属性的每种类型添加映射(例如,从 EF 'Address' 类型到 POCO 'Address' 类型的映射)。

这实际上相当简单,但您可能需要设置一些 AutoMapper 配置。 您的存储过程实际上只能返回扁平化的结果,但您仍然可以传递所有关系的所有字段。 如果您想几乎免费配置,您实际上只需要让您的存储过程以扁平格式返回属性名称。 例如, AddressCity而不是City之类的东西。 如果正在映射的对象,你有一个像一个属性AddressCity ,并会映射对象,你有一个导航属性Address ,它本身有一个属性City ,AutoMapper会自动在适当的填补了这一。 如果您不想或不能更改存储过程返回的列名,那么您只需配置 AutoMapper:

AutoMapper.Mapper.CreateMap<Customer_GetCustomers_Result, Custom>()
    .ForMember(dest => dest.Address, opts => opts.MapFrom(src => new Address
    {
        City = src.City,
        // etc.
    });

如果您有更复杂的场景,例如可枚举的导航属性,则此方法将不起作用。 在这种情况下,最好的办法是分多个步骤进行,这样您就可以使用一个存储过程来检索主要对象以及可以用它展平的所有内容。 这样,您就可以映射到您想要的类型。 然后,使用单独的存储过程根据主对象的 id 或其他内容查找可枚举项,并将它们映射到先前映射对象上的可枚举属性。

public IEnumerable<object> sample()
   {


        using (SqlConnection con = new SqlConnection(connStr))
        {
            DataTable dt = new DataTable();
            SqlCommand cmd = new SqlCommand("proedurename", con);
            cmd.CommandType = CommandType.StoredProcedure;
            if (cmd.Connection.State != ConnectionState.Open)
                cmd.Connection.Open();

            var retObject = new List<dynamic>();
            using (var dataReader = cmd.ExecuteReader())
            {
                while (dataReader.Read())
                {
                    var dataRow = new ExpandoObject() as IDictionary<string, object>;
                    for (var iFiled = 0; iFiled < dataReader.FieldCount; iFiled++)
                    {
                        dataRow.Add(
                            dataReader.GetName(iFiled),
                            dataReader.IsDBNull(iFiled) ? null : dataReader[iFiled] // use null instead of {}
                        );
                    }

                    retObject.Add((ExpandoObject)dataRow);
                }
            }
            return retObject;
        }

    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM