模型类中的EF上下文

3
在我们的Web.API项目中,我们使用Entity Framework 6。我们有一个DataModel类,其中包含DatabaseContext。DataModel是一个[ThreadStatic]单例。
就像这样:
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并使用依赖注入来管理数据库上下文时。
我的问题是,是否有更加优雅的模式可以解决这个问题?依赖注入在这里行不通,因为Entity Framework生成了模型对象。或者,如果我们将这段代码从部分类移动到例如一个工具类中,会更好吗?但是如何在那里注入上下文呢?

1
单例上下文和在实体类中使用上下文都是反模式。所以首先尝试摆脱这些模式,不要担心依赖注入。你会发现,在此之后,将代码转换为依赖注入会更容易。如何做到这一点太过依赖于你的架构的其他部分,无法对此做出明智的建议。 - undefined
这个数据模型位于哪一层?它是API返回的模型,还是尝试抽象数据库层?通常我建议使用仓储模式,但并不适用于所有问题。让模型通过数据库调用自行填充(“活动记录模式”)通常会引起更多问题。 - undefined
使用正确的外键可以解决该问题。作业与CreatedBy用户相关,而不是用户名(除非用户名是您的用户表中的主键,在这种情况下您应重新考虑)。在EF中映射该关系,然后您可以使用延迟加载(如果实体已附加)或者在查询中使用Include子句立即检索CreatedByUser。您当前的解决方案不是线程安全的,特别是考虑到您有一个具有多个线程的asp.net应用程序(至少同时请求1次)。 - undefined
工作模型是由EF创建的。我们已经讨论过使用外键,但我们决定不使用它。但现在,使用它更有意义。我们将修复这个反模式。谢谢! - undefined
1个回答

0

通常情况下,你应该避免让模型意识到它们的创建和使用上下文,因为这种知识应该是自顶向下而不是自底向上的。除此之外,你会遇到像你现在经历的设计问题。你可以尝试在应用程序层面通过扩展方法、控制反转框架、实用方法、POCO等方式来解决这个问题,但归根结底,你只是在解决一个问题,这个问题只存在于你的底层数据库模式设计不足以满足你的预期使用。

例如,你的Job表中有一个对创建该作业的用户的用户名的引用。为什么要这样做呢?用户名可能会发生变化,而且每当你想要获取该用户的其他关键属性时,你都需要执行二次查找(就像你在部分类中所做的那样)。如果你改为让Job表维护对User表的外键引用,你只需在C#端使用导航属性即可获取完整的用户对象,只要查询中包含了适当的相关实体。你甚至不需要部分类,而且你的数据库模式将变得更易维护,这是额外的好处。

有时候,简化数据库设计以简化代码是最好的选择。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接