我正在使用ASP.net中的依赖注入开发我的第一个数据驱动域。
在我的数据访问层中,如果创建了一些域数据模型,例如:
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; }
}
然后我开发了一个接口,如下所示:
public interface ICompanyService {
IEnumerable<Model.Company> GetCompanies();
IEnumerable<Model.Employee> GetEmployees();
IEnumerable<Model.Employee> GetEmployees(Guid companyId);
}
在一个单独的模块中,我使用Linq to Sql实现了这个接口:
public class CompanyService : ICompanyService {
public IEnumerable<Model.Employee> GetEmployees();
{
return EmployeeDb
.OrderBy(e => e.Name)
.Select(e => e.ToDomainEntity())
.AsEnumerable();
}
}
其中,ToDomainEntity()在employee存储库类中作为基本实体类的扩展方法实现:
public Model.EmployeeToDomainEntity()
{
return new Model.Employee {
EmployeeId = this.EmployeeId,
CompanyId = this.CompanyId,
Name = this.Name
};
}
到目前为止,我已经或多或少地遵循了Mark Seeman的优秀著作“.NET中的依赖注入”中描述的模式-所有的模式都运行得很好。
但是,我想扩展我的基本模型,使其也包括关键参考模型,因此域Employee类将变为:
public class Employee {
public Guid EmployeeId { get; set; }
public Guid CompanyId { get; set; }
public Company { get; set; }
public string Name { get; set; }
}
并且ToDomainEntity()函数将被扩展为:
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调用来填充树的每个节点/子节点)。
如果我以内联方式创建数据模型...
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,那么使用填充模型的正确方法是什么,而不必求助于创建内联赋值块来构建表达式树?
任何帮助/建议都将不胜感激。
发布于 2012-07-13 08:14:26
这个问题是由于同时具有数据层实体和域层实体,并且需要两者之间的映射而引起的。虽然您可以让它工作,但这会使一切变得非常复杂,就像您已经经历过的那样。由于性能原因以及其他业务逻辑和表示逻辑将需要不同的数据,您正在进行数据和域之间的映射,并且很快将为这些相同的实体添加更多的映射。
唯一真正的解决方案是丢弃数据实体,并创建可直接序列化到后端存储(SQL server)的POCO模型对象。
POCO实体是LINQ to SQL从一开始就支持的东西,但我认为迁移到Entity Framework Code First会更好。
这样做时,您可以从存储库公开IQueryable<T>
接口(您当前将存储库称为ICompanyService
,但更好的名称应该是ICompanyRepository
)。这使您可以进行高效的LINQ查询。当直接通过查询提供程序进行查询时,可以防止加载完整的实体。例如:
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应用程序中进行筛选相比)。
发布于 2012-07-12 22:03:37
您可以要求Linq2Sql使用DataLoadOptions.LoadWith
方法预加载某些实体(而不是延迟加载它们),请参阅:http://msdn.microsoft.com/en-us/library/bb534268.aspx。如果您对Company
实体执行此操作,那么我认为Linq2Sql将不必访问数据库来再次获取它。
https://stackoverflow.com/questions/11449645
复制相似问题