【发布时间】:2017-11-25 20:04:33
【问题描述】:
在我们的 Web.API 项目中,我们使用 Entity Framework 6。我们有一个包含 DatabaseContext 的 DataModel 类。 DataModel 是 [ThreadStatic] Singleton。
像这样:
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 生成模型对象。或者,如果我们将此代码从部分类移动到例如,它会更好吗?一个实用类?但是我们怎样才能在那里注入上下文呢?
【问题讨论】:
-
单例上下文和在实体类中使用上下文都是反模式。所以首先尝试摆脱这些模式,而不用担心 DI。您会看到,在那之后,将代码转换为 DI 会容易得多。 如何做到这一点在很大程度上取决于你的架构的其余部分,无法说出任何明智的说法。
-
这个数据模型位于哪一层?是 API 返回的模型,还是数据库抽象层的尝试?一般来说,我建议使用存储库模式,但这并不适合所有问题。让模型通过数据库调用(“活动记录模式”)自行填充通常会导致比它解决的问题更多的问题。
-
使用正确的外键可以解决问题。作业与 CreatedBy 用户 on UserId 相关,而不是用户名(除非用户名是您的用户表中的 PK,在这种情况下您应该重新考虑)。在 EF 中映射该关系,然后您可以在附加实体时使用延迟加载导航到
CreatedByUser,或者使用查询中的Include子句立即检索它。您当前的解决方案不是线程安全的,尤其是考虑到您有一个具有多个线程的 asp.net 应用程序(至少 1x 并发请求)。 -
作业模型由 EF 创建。我们已经讨论过使用外键,但我们决定反对它。但现在,使用它更有意义。我们将修复反模式。谢谢!
标签: c# entity-framework dependency-injection