【问题标题】:Using AutoMapper with EF6 DbFirst and Stored Procedure (complex types)将 AutoMapper 与 EF6 DbFirst 和存储过程一起使用(复杂类型)
【发布时间】:2015-01-16 04:30:19
【问题描述】:

我正在使用 Entity Framework 6 DBFirst、MVC5 和 AutoMapper。

我有 2 个表,Customers 和 CustomerContacts 对于我在实体框架 EDMX(自动生成)中的每个类,我都有一个具有完全相同属性的模型类。即客户 => Model.Customer,CustomerContact => Model.CustomerContact。这就是我使用 AutoMapper 的原因。

问题 1:由于我的 Customer_Get 存储过程返回一个自动生成的复杂类型 (Customer_Get_Result),因此大多数人还会为此创建一个额外的模型类吗? (Model.Customer_Get_Result.cs) 还是应该将所有属性组合起来,将所有内容添加到 Model.Customer?

问题 2:我处理以下客户联系人映射的方式是否正确?大部分 Model.Customer 中的每个属性都与 AutoGenerated EF6 DBFirst 文件完全相同,除了我放在 Model.Customer 中的这个:

public List<CustomerContact> Contacts { get; set; }

最后我希望能够使用 Customer.Contacts 自动获取所有客户联系人的列表

在我的 AutoMapper 中,我试图做这样的事情,但不认为这是正确的:

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

    //map for customer getlist stored proc which will be returning several fields
    //such as TotalCount, RowNumber, fields from a bunch of other tables
    CreateMap<Customer_Get_Result, Model.Customer>();

【问题讨论】:

    标签: c# asp.net-mvc entity-framework automapper ef-database-first


    【解决方案1】:

    对于存储过程的复杂类型 (Customer_Get_Result) 人们也为此制作了一个额外的模型类?

    如果它与客户的属性完全相同,那么我可能不会仅为它创建模型,而只是将其映射到现有模型。

    虽然这取决于您对这个 Model 类所做的事情,以及从实体映射的数据的用例是否与从存储过程映射的数据有任何不同。模型只是 POCO 的一个花哨的术语。模型通常是两件事之一。实体的简化,比 EF 实体更接近 POCO;例如您可能在业务层和数据库层之间使用的 DTO。或者它是针对特定上下文的专门化,例如仅具有特定视图所需属性的 ViewModel,并且通常包含特定于 UI 的数据注释等内容。

    这在很大程度上取决于您的应用程序是如何分层的,应用程序的哪一部分正在检索数据,以及它打算如何处理这些数据。也就是说,我可能会先使用相同的模型,然后看看我是否觉得需要 rafactor(但您仍然需要 2 个映射,一个来自 SP_Complex_Type -> Model,一个来自 Entity -> Model)。

    看起来您的 DB/EF 模型只有一个来自 Customer.CustomerContact 的相关联系人,但您的模型具有一对多关系 Model.Customer.Contacts。我仅基于多个属性名称,因为您没有向我们提供您的实体的任何声明。无论哪种方式您的 EF 实体支持的关系与您的模型支持的关系不匹配。您可以在此处使用 AutoMapper 做很多不同的事情,但在您弄清楚为什么一个有相关联系人列表而另一个只有一个相关联系人之前,您无法做出决定。

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

    当将列表映射到列表时,并且属性名称不同,那么上面的内容正是您要做的。此外,如果每个列表中的类型不同,那么您需要确保您之前为这些类型声明了一个映射。例如,如果您要从List&lt;CustomerContactEntity&gt;List&lt;CustomerContactModel&gt;,那么您需要已经完成CreateMap&lt;CustomerContactEntity,CustomerContactModel&gt; 来告诉AutoMapper 它可以转换这些类型。这样,当它遇到列表中的每个项目时,它会看到它具有该子类型的映射。

    【讨论】:

    • 非常感谢您的描述性回答,它清除了一些事情。我不确定你的意思是什么我的表名是 CustomerContact,我不确定为什么 Entity Framework 没有根据我在 SQLServer 中创建的关系将它创建的 Navigation 属性复数化为 CustomerContacts 而不是 CustomerContact,但现在让我们假设它是具有导航属性的一对多。我的项目结构如下:.Web(MVC5), .Business(Services, RepoInterfaces, ServiceInterfaces, Logic), .Data(Strictly EF6 EDMX, Repositories), .Model(POCO classes)。
    • 一切都引用模型,数据引用业务,Web 引用业务。通常在一个简单的 MVC5 应用程序中,我会使用没有 POCO 概念的 DBFirst,并且只能在 linq 中使用 Customer.Contacts。有了这种增强的项目结构和 POCO 类/AutoMapper 的添加,当涉及到一对多关系和映射时,我有点困惑。
    • 那么你会建议如何在我的 Customer/details.cshtml 中显示客户联系人。我可以在我的 razor 页面中访问我的客户的基本信息,因为它是页面的主要模型。会不会像在 razor 中循环遍历 Customer.Contacts 一样简单?
    • @user2272527 .Include 是一种可以在 EF 查询中调用的方法。因此,它需要在您进行 EF 查询的 GetCustomerByID 内。当然,您可能并不总是想要子项,因此 GetCustomerByID 可能需要一个 , bool includeContacts) 参数,或者有些人使用存储库模式,其中他们的数据库层函数不返回实体,而是返回 IQueryable 以便您可以添加其他在返回时调用.Include,这样调用者就可以决定他们想要什么额外的标准和数据。
    猜你喜欢
    • 1970-01-01
    • 2018-10-24
    • 1970-01-01
    • 1970-01-01
    • 2012-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多