Asp.net mvc 3 在ASP.NET MVC3中,如何在不创建组件之间耦合的情况下获取属于相关DB表的数据?
我在C#和Razor中有一个ASP.NETMVC3。应用程序的体系结构分为数据访问层(EF类+存储库)、服务层、控制器、视图模型和视图 我有两个EF类Asp.net mvc 3 在ASP.NET MVC3中,如何在不创建组件之间耦合的情况下获取属于相关DB表的数据?,asp.net-mvc-3,repository,viewmodel,service-layer,coupling,Asp.net Mvc 3,Repository,Viewmodel,Service Layer,Coupling,我在C#和Razor中有一个ASP.NETMVC3。应用程序的体系结构分为数据访问层(EF类+存储库)、服务层、控制器、视图模型和视图 我有两个EF类产品(keyProdId)和ProductCategories(keyProductCategoryId) 它们通过类产品中的ProdCatId上的一对多关系关联为外键和类产品类别中的ProductCategoryId 当然,从classProducts到ProductCategories还有一个导航属性 我的存储库类中有以下方法: public
产品
(keyProdId
)和ProductCategories
(keyProductCategoryId
)
它们通过类产品中的ProdCatId
上的一对多关系关联为外键和类产品类别中的ProductCategoryId
当然,从classProducts
到ProductCategories
还有一个导航属性
我的存储库类中有以下方法:
public IQueryable<Products> GetAllProducts()
{
return productDB.Products;
}
为了在视图中包含这些信息,我应该从我的服务层使用这些代码,或者从我的视图模型使用更糟的代码。然而,通过这种方式,我在我想要保持分离的组件(服务层和EF或ViewModel和EF)之间创建了耦合
如果我从我的存储库(方法string GetProductCategory(int ProdId)
)将此值与GetAllProducts().ToList()
)一起获取到我的服务层,我将有两个对象:
1) A列表
2) 一个字符串
如何将这些值传递给控制器,然后包装到ViewModel中?我是否应该在我的服务层中创建一个类ProductInfo
,用于包装此数据?
此解决方案在控制器、视图模型和类产品信息之间创建耦合
不创建耦合的正确做法是什么?两个考虑因素。
1) 将代码更改为
repository.GetAllProducts().Products.Where(n => n.ProdId == prodId)
.Select(m => m.hasCategory.ProductCategoryName).First();
这样代码是EF不可知的,它只使用延迟执行。。。这意味着它将与支持Linq的所有组件(Linq2Sql、EF、NHibernate等)一起工作
(p>2)考虑解决问题简单地隐藏产品对象的属性。这意味着不要以懒惰的方式加载它们。
只有在使用在存储库或服务层中管理会话的方法时,这才有意义。如果您有某种类型的按请求会话方法,您的属性(product.hasCategory.ProductCategoryName)将在需要时填充。您的产品和ProductCategory是域模型,而不是视图模型。Google viewmodels和domain models可以更好地理解它们之间的区别
如果我是你,我会创建一个名为ProductInfoViewModel的视图模型。此类将仅包含要显示的有关产品的信息
public class ProductInfoViewModel
{
public string Name { get; set; }
public string Category { get; set; }
}
现在您有了一个简单的类,它将用于显示一些数据
是的,您仍然希望调用存储库或服务层以获取产品数据:
var productDomainModel = productDB.Products.Where(n => n.ProdId == prodId)
.Select(m => m.hasCategory.ProductCategoryName).First();
现在,您可以创建产品视图模型,而不是将productDomainModel传递给您的视图,该模型将更轻松,因为它将只包含您希望显示的属性:
var productViewModel = new ProductViewModel
{
Name = productDomainModel .Name,
Category = productDomainModel .Category
}
现在可以将此视图模型传递到视图:
return View(productViewModel);
您的视图现在知道一个视图模型,但它对您的域模型一无所知,这是一件好事,它促进了关注点的分离
还有一件事,当我们从产品域模型创建产品视图模型时,我们编写了“样板”代码,例如Name=product.Name
现在,您有20个属性,您可能希望多次将域模型映射到视图模型。这是一个繁琐的工作,你可以通过谷歌工具,如Automapper来避免它
祝你好运谢谢你的提示。你的答案不是我想要的。真正的问题是将这些数据从数据库带到视图,而不在不同层之间创建耦合。此外,我不喜欢有很多内存中的对象,我相信至少在存储库层使用延迟加载和延迟执行可以实现我想要的。我不明白你的意思。在我在第1点中编写的代码中,应该在您的服务层上,我只使用存储库层(直接在下面的那个)。然后从控制器调用该方法(我允许控制器和服务层之间的连接)。而您的存储库拥有GetAllProducts()方法,是唯一了解EF的存储库,因为它使用productDB,EF上下文。我的示例在哪里打破了层的分离?我不希望在我的服务层中有查询。我宁愿将您编写的代码放在我的存储库中,并使用存储库公开的方法,而不是将其放在我的服务层中。像这样,EF和服务层之间存在耦合。然后,您应该在服务层中公开一个方法,该方法只调用实际执行查询的underline repository方法。这样,您就可以通过服务将控制器从存储库中解耦,并且在服务中不会有任何查询。只需在服务和存储库之间使用1:1映射方法即可解决您的上一个问题。谢谢您的回答。但是,对于您的代码var productDomainModel=productDB.Products.Where(n=>n.ProdId==ProdId)。选择(m=>m.hascegory.ProductCategoryName).First()
aProductCategories
投影只包含ProductCategories
字段。
return View(productViewModel);