Asp.net mvc 3 在ASP.NET MVC3中,如何在不创建组件之间耦合的情况下获取属于相关DB表的数据?

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

我在C#和Razor中有一个ASP.NETMVC3。应用程序的体系结构分为数据访问层(EF类+存储库)、服务层、控制器、视图模型和视图

我有两个EF类
产品
(key
ProdId
)和
ProductCategories
(key
ProductCategoryId

它们通过类
产品中的
ProdCatId
上的一对多关系关联为外键和类
产品类别中的
ProductCategoryId

当然,从class
Products
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()
a
ProductCategories
投影只包含
ProductCategories
字段。
return View(productViewModel);