首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何有效地填充数据访问层模型?

如何有效地填充数据访问层模型?
EN

Stack Overflow用户
提问于 2012-07-12 18:12:16
回答 2查看 426关注 0票数 0

我正在使用ASP.net中的依赖注入开发我的第一个数据驱动域。

在我的数据访问层中,如果创建了一些域数据模型,例如:

代码语言:javascript
代码运行次数:0
运行
复制
public class Company {
   public Guid CompanyId { get; set; }
   public string Name { get; set; }
}

public class Employee {
   public Guid EmployeeId { get; set; }
   public Guid CompanyId { get; set; }
   public string Name { get; set; }
}

然后我开发了一个接口,如下所示:

代码语言:javascript
代码运行次数:0
运行
复制
public interface ICompanyService {
   IEnumerable<Model.Company> GetCompanies();
   IEnumerable<Model.Employee> GetEmployees();
   IEnumerable<Model.Employee> GetEmployees(Guid companyId);
}

在一个单独的模块中,我使用Linq to Sql实现了这个接口:

代码语言:javascript
代码运行次数:0
运行
复制
public class CompanyService : ICompanyService {

    public IEnumerable<Model.Employee> GetEmployees();
    {
        return EmployeeDb
            .OrderBy(e => e.Name)
            .Select(e => e.ToDomainEntity())
            .AsEnumerable();
    }
}

其中,ToDomainEntity()在employee存储库类中作为基本实体类的扩展方法实现:

代码语言:javascript
代码运行次数:0
运行
复制
public Model.EmployeeToDomainEntity()
{
     return new  Model.Employee {
         EmployeeId = this.EmployeeId,
         CompanyId = this.CompanyId,
         Name = this.Name
     };
}

到目前为止,我已经或多或少地遵循了Mark Seeman的优秀著作“.NET中的依赖注入”中描述的模式-所有的模式都运行得很好。

但是,我想扩展我的基本模型,使其也包括关键参考模型,因此域Employee类将变为:

代码语言:javascript
代码运行次数:0
运行
复制
public class Employee {
   public Guid EmployeeId { get; set; }
   public Guid CompanyId { get; set; }
   public Company { get; set; }
   public string Name { get; set; }
}

并且ToDomainEntity()函数将被扩展为:

代码语言:javascript
代码运行次数:0
运行
复制
public Model.Employee ToDomainEntity()
{
     return new  Model.Employee {
         EmployeeId = this.EmployeeId,
         CompanyId = this.CompanyId,
         Company = (this.Company == null) ? null : this.Company.ToDomainEntity()
         Name = this.Name
     };
}

我怀疑,从领域建模的角度来看,这可能是“糟糕的做法”,但我认为,如果我要开发一个特定的视图模型来实现同样的目的,我遇到的问题也会成立。

本质上,我遇到的问题是填充数据模型的速度/效率。如果我使用上面描述的ToDomainEntity()方法,Linq to Sql将创建一个单独的SQL调用来检索每个雇员的公司记录的数据。正如您所期望的那样,这大大增加了计算SQL表达式所需的时间(在我们的测试数据库上从大约100ms增加到7秒),特别是在数据树很复杂的情况下(因为要进行单独的SQL调用来填充树的每个节点/子节点)。

如果我以内联方式创建数据模型...

代码语言:javascript
代码运行次数:0
运行
复制
public IEnumerable<Model.Employee> GetEmployees();
{
    return EmployeeDb
        .OrderBy(e => e.Name)
        .Select(e => new Model.Employee {
            EmployeeId = e.EmployeeId,
            /* Other field mappings */
            Company = new Model.Company {
               CompanyId = e.Company.CompanyId,
               /* Other field mappings */
            }
        }).AsEnumerable();
}

Linq to SQL生成了一条漂亮、紧凑的SQL语句,该语句本机使用“inner”方法将公司与员工关联起来。

我有两个问题:

1)从域类对象中引用关联的数据类是否被认为是“糟糕的做法”?

2)如果是这种情况,并且为此创建了一个特定的View Model,那么使用填充模型的正确方法是什么,而不必求助于创建内联赋值块来构建表达式树?

任何帮助/建议都将不胜感激。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-07-13 16:14:26

这个问题是由于同时具有数据层实体和域层实体,并且需要两者之间的映射而引起的。虽然您可以让它工作,但这会使一切变得非常复杂,就像您已经经历过的那样。由于性能原因以及其他业务逻辑和表示逻辑将需要不同的数据,您正在进行数据和域之间的映射,并且很快将为这些相同的实体添加更多的映射。

唯一真正的解决方案是丢弃数据实体,并创建可直接序列化到后端存储(SQL server)的POCO模型对象。

POCO实体是LINQ to SQL从一开始就支持的东西,但我认为迁移到Entity Framework Code First会更好。

这样做时,您可以从存储库公开IQueryable<T>接口(您当前将存储库称为ICompanyService,但更好的名称应该是ICompanyRepository)。这使您可以进行高效的LINQ查询。当直接通过查询提供程序进行查询时,可以防止加载完整的实体。例如:

代码语言:javascript
代码运行次数:0
运行
复制
from employee in this.repository.GetEmployees()
where employee.Company.Name.StartWith(searchString)
select new 
{
    employee.Name, 
    employee.Company.Location 
};

在使用IQueryable<T>时,LINQ to SQL和实体框架会将其转换为一个非常有效SQL查询,该查询只返回数据库中的雇员姓名和公司位置,并在数据库中进行筛选(与GetEmployees()返回IEnumerable<T>时在.NET应用程序中进行筛选相比)。

票数 1
EN

Stack Overflow用户

发布于 2012-07-13 06:03:37

您可以要求Linq2Sql使用DataLoadOptions.LoadWith方法预加载某些实体(而不是延迟加载它们),请参阅:http://msdn.microsoft.com/en-us/library/bb534268.aspx。如果您对Company实体执行此操作,那么我认为Linq2Sql将不必访问数据库来再次获取它。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11449645

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档