代码之家  ›  专栏  ›  技术社区  ›  Gup3rSuR4c

如何在DataContext类中从中公开DataContext?

  •  2
  • Gup3rSuR4c  · 技术社区  · 14 年前

    在DataContext中扩展类时是否可以公开DataContext?考虑一下:

    public partial class SomeClass {
        public object SomeExtraProperty {
            this.DataContext.ExecuteQuery<T>("{SOME_REALLY_COMPLEX_QUERY_THAT_HAS_TO_BE_IN_RAW_SQL_BECAUSE_LINQ_GENERATES_CRAP_IN_THIS INSTANCE}");
        }
    }
    

    我该怎么做呢?我现在有一个草率的版本在工作,我把DataContext传递给视图模型,然后从那里传递给我在partial类中设置的方法。我想避免整个数据上下文的传递,只需要有一个我可以引用的属性。

    @Aaronaught的更新

    假设我有一个非常简单的应用程序,结构如下(在文件夹中):

    • 控制器
    • 意见

    存储库文件放在哪里?在“模型”文件夹中,还是可以仅为它们创建“存储库”文件夹?

    过去,存储库如何知道数据上下文?我需要在存储库的每个方法中创建一个新的实例吗(如果是这样的话,看起来很有效。。。这不会导致从一个实例中提取一个对象并在使用另一个实例的控制器中使用它时出现问题?

    例如,我当前有此设置:

    public class BaseController : Controller {
        protected DataContext dc = new DataContext();
    }
    
    public class XController : BaseController {
        // stuff
    }
    

    这样,我就有了一个“全局”数据上下文,可供继承自 BaseController . 我的理解是这是有效的(我可能错了…)。

    public class BaseCollection {
        // Common properties for the Master page
    }
    
    public class XCollection : BaseCollection {
        // X View specific properties
    }
    

    那么,将所有这些放在何处以及如何使用存储库插件呢?会是这样吗(使用我的应用程序的真实对象):

    public interface IJobRepository {
        public Job GetById(int JobId);
    }
    
    public class JobRepository : IJobRepository {
        public Job GetById(int JobId) {
            using (DataContext dc = new DataContext()) {
                return dc.Jobs.Single(j => (j.JobId == JobId));
            };
        }
    }
    

    还有,接口的作用是什么?是不是其他服务可以连接到我的应用?如果我不打算拥有这样的能力呢?

    接下来,最好有一个抽象对象来收集真实对象的所有信息吗?例如 IJob 对象,它将具有 Job Name ? 存储库也会更改为:

    public interface IJobRepository {
        public IJob GetById(int JobId);
    }
    
    public class JobRepository : IJobRepository {
        public IJob GetById(int JobId) {
            using (DataContext dc = new DataContext()) {
                return dc.Jobs.Single(j => new IJob {
                    Name = dc.SP(JobId)  // of course, the project here is wrong,
                                         // but you get the point...
                });
            };
        }
    }
    

    我现在头昏脑胀。我希望从头到尾都能看到一个教程,即“File->New->Do this->Do that”。

    2 回复  |  直到 14 年前
        1
  •  5
  •   Aaronaught    14 年前

    老实说,这不是Linq to SQL设计的那种场景。Linq-to-SQL本质上是数据库的一层薄薄的表面;实体模型应该与数据模型紧密地映射,而且通常Linq-to-SQL“实体模型”不适合用作域模型(MVC中的“模型”)。

    您的控制器应该使用某种类型的存储库或服务。应该由该对象负责加载特定实体 视图模型所需的任何其他数据。如果你没有一个存储库/服务,你可以直接将这个逻辑嵌入控制器,但是如果你经常这样做,那么你最终会得到一个脆弱的设计,很难维护-最好从一开始就有一个好的设计。

    尝试设计实体类以引用 DataContext . 这正是像Linq to SQL这样的ORMs试图解决的问题 避免 . 如果你的实体真的意识到 然后,它们违反了Linq to SQL提供的封装,并将实现泄漏给公共调用方。

    你需要有 类应该知道 数据上下文 数据上下文

    P、 有些人会坚持 存储库 服务 建设者


    假设您正在构建一个汽车交易网站,需要显示有关域模型(实际汽车/上市)的信息,以及一些必须单独获取的相关但未链接的信息(假设该特定模型的价格范围)。所以你会有一个这样的视图模型:

    public class CarViewModel
    {
        public Car Car { get; set; }
        public decimal LowestModelPrice { get; set; }
        public decimal HighestModelPrice { get; set; }
    }
    

    视图模型生成器可以如此简单:

    public class CarViewModelService
    {
        private readonly CarRepository carRepository;
        private readonly PriceService priceService;
    
        public CarViewModelService(CarRepository cr, PriceService ps) { ... }
    
        public CarViewModel GetCarData(int carID)
        {
            var car = carRepository.GetCar(carID);
            decimal lowestPrice = priceService.GetLowestPrice(car.ModelNumber);
            decimal highestPrice = priceService.GetHighestPrice(car.ModelNumber);
            return new CarViewModel { Car = car, LowestPrice = lowestPrice,
                HighestPrice = highestPrice };
        }
    }
    

    CarRepository 是一个存储库 数据上下文 Cars ,和 PriceService 本质上包装了一堆存储过程 数据上下文 .

    方式 更容易维护。


    更新:新问题的答案

    如果存储库负责持久化模型类,则它们是模型的一部分。如果它们处理视图模型(也称为“服务”或“视图模型构建器”),那么它们是表示逻辑的一部分;从技术上讲,它们介于控制器和模型之间,这就是为什么在我的MVC应用程序中,我通常都有 Model 命名空间(包含实际的域类)和 ViewModel 命名空间(包含表示类)。

    存储库如何知道数据上下文?

    在大多数情况下,您会希望通过构造函数传递它。这允许您共享相同的 数据上下文 跨多个存储库的实例,当您需要 回写 包含多个域对象的视图模型。

    数据上下文 作为HTTP请求范围)。通常你的控制器不应该创建 数据上下文

    在我的Models文件夹中,我有一个“Collections”文件夹,它实际上充当ViewModels

    这是错误的。视图模型不是您的模型。视图模型属于视图,它独立于域模型(这就是“M”或“Model”所指的)。如上所述,我建议创建一个 视图模型 命名空间以避免 Views

    那么,将所有这些放在何处以及如何使用存储库插件呢?

    请参阅上面的几段-存储库应该注入 控制器应该被注入到存储库中。如果您没有使用DI框架,那么可以让控制器创建 和存储库,但尽量不要太过巩固后一个设计,你会想清理它以后。

    主要是为了在需要时更改持久性模型。也许你认为LINQtoSQL过于面向数据,你想切换到更灵活的实体框架或NHiBernt。也许您需要实现对Oracle、mysql或其他一些非Microsoft数据库的支持。或者,您可能完全打算继续使用Linq to SQL,但希望能够为控制器编写单元测试;唯一的方法是将模拟/假存储库注入控制器,并且要使其工作,它们必须是抽象类型。

    接下来,最好有一个抽象对象来收集真实对象的所有信息吗?例如 IJob 对象,它将具有 Job Name ?

    这或多或少是我最初推荐的,尽管您已经使用了一个很难调试的投影。最好在单独的代码行上调用SP,然后将结果合并起来。

    此外,不能为域或视图模型使用接口类型。它不仅是错误的隐喻(模型代表了应用程序的不可改变的规律,它们不是 除非现实世界的需求发生了变化,否则是不可能的;接口不能被数据绑定,因为在发布时没有任何东西可以实例化。

    所以是的,你的想法是对的,除了(a)而不是 应该是你的 JobViewModel ,(b)代替 IJobRepository 应该是 JobViewModelService ,和(c)而不是直接实例化 数据上下文 它应该通过构造函数接受一个。

    如果你有一个24小时的最后期限,那么你仍然可以 把所有这些逻辑直接推到控制器中。只是不要让它太久,否则你的控制器将(d)演变成上帝对象憎恶。

        2
  •  1
  •   Omar    14 年前

    替换 {SOME_REALLY_COMPLEX_QUERY_THAT_HAS_TO_BE_IN_RAW_SQL_BECAUSE_LINQ_GENERATES_CRAP_IN_THIS INSTANCE} 使用存储过程,然后让Linq to SQL导入该函数。

    然后可以直接从数据上下文调用该函数,获取结果并将其传递给视图模型。