2017-06-22 32 views
1

在我们的Web.API项目中,我们使用实体框架6.我们有一个DataModel类,它包含DatabaseContext。 DataModel是一个[ThreadStatic] Singleton。模型类中的EF上下文

像这样:

public class DataModel 
{ 
    [ThreadStatic] private static DataModel _instance; 
    public static DataModel Instance => _instance ?? (_instance = new DataModel()); 

    public DatabaseContext Context { get; private set; } 

    private DataModel() 
    { 
     Context = NewContext(); 
    } 
} 

现在,在我们的(部分)模型类之一,我们使用的情况下是这样的:

public partial class Job 
{ 
    public User CreatedByUser 
    { 
     get { return DataModel.Instance.Context.Users.FirstOrDefault(d => d.Username == CreatedBy); } 
    } 
} 

我们在另一个数据库中的表对应的用户搜索。这是有效的,但在我看来,这不是一个美丽的解决方案。特别是如果我们计划将我们的项目迁移到.NET Core并对数据库上下文使用依赖注入。

我的问题是,有没有一种模式,它解决了更优雅的问题?依赖注入在这里不起作用,因为实体框架生成模型对象。或者,如果我们将这些代码从部分类移动到例如一个util类?但是我们怎么能在那里注入上下文呢?

+1

实体类中的单例上下文和上下文都是反模式。所以首先尝试摆脱这些模式,而不用担心DI。之后你会看到,将代码转换为DI会更容易。 *如何做到这一点,很大程度上取决于你的架构的其他部分,以便对其进行任何明智的说明。 –

+0

这个datamodel驻留在什么层?它是从API返回的模型还是尝试在数据库抽象层?通常我会建议使用存储库模式,但这并不适合所有问题。让模型通过数据库调用(“活动记录模式”)填充自己通常会导致比解决问题更多的问题。 – CodeCaster

+0

使用正确的外键可以解决问题。作业是通过UserId *上的CreatedBy用户*关联的,而不是用户名(除非用户名是用户表中的PK,在这种情况下,您应该重新考虑这一点)。在EF中映射该关系,然后如果实体已连接,则可以使用延迟加载导航到“CreatedByUser”,或者在查询中使用“包含”子句立即检索它。您当前的解决方案不是线程安全的,特别是考虑到您有一个具有多个线程的asp.net应用程序(至少1x同时请求)。 – Igor

回答

0

您通常希望避免要求您的模型意识到其创建和使用环境,因为该知识应该是自上而下,而不是自下而上。除其他原因外,您会遇到像您现在遇到的设计问题。您可以尝试在应用程序级别上使用扩展方法,控制框架反转,实用方法,pocos等设计解决方案,但是在一天结束时,您试图解决仅存在的问题,因为您的基础数据库模式没有适合您的预期用法。

例如,您的Job表中引用了创建它的用户的用户名。为什么?用户名可能会改变,并且任何时候您想要该用户的额外关键属性都需要执行辅助查找(就像您在部分班级中所做的那样)。如果您将Job表保留为User表的外键,那么只要查询中包含适当的相关实体,就可以在C#端使用导航属性来获取完整的用户对象。你甚至不需要部分类,你的数据库模式将变得更加可维护,作为额外的奖励。

有时最好简化数据库设计以简化代码。

相关问题