我如何在项目B中使用项目A中的UserManager?

问题描述 投票:0回答:1

项目A和项目B均为ASP NET Core 2.2应用程序。

项目B使用Hangfire进行后台工作,而仅执行其他操作,因此使用Hangfire的事实甚至可能都不重要(在底部对此进行更多说明)。项目A在B的Hangfire上安排了工作。

现在,假设我的班级代表一个任务,叫做乔布。它包含在项目C中,该项目C是项目B引用的普通旧类库,并且依次引用了其他包含其正在使用的实体的项目。

依赖关系将通过构造函数注入到此类中:

public class Job
{
    public Job(UserManager<ApplicationUser> userManager,
               IThisRepository thisRepository,
               IThatRepository thatRepository)
    {
    }

    public void Execute(string userId)
    {
        // this is where the work gets done
    }
}

并且在大多数情况下,它们do被注入:IThisRepositoryIThatRepository被注入,并且它们主要起作用...

在项目B的Startup.cs中,应该运行此作业,我手动并成功注册了这些接口,以及它们需要其他内容的DbContext

由于构造函数需要所有参数,因此UserManager很难手动注册,因此,由于我在工作中不需要[[really,因此我决定进行一些更改。

现在,我正在使用的实体的示例如下:

public class Category { [Key] public int Id { get; set; } // several other properties of primitive types public ApplicationUser User { get; set; } [Required] public string UserId { get; set; } } public class Dish { [Key] public int Id { get; set; } // several other properties of primitive types public ApplicationUser User { get; set; } [Required] public string UserId { get; set; } public Category Category { get; set; } [Required] public string CategoryId { get; set; } }

现在的问题是这样的:在Job内,我尝试创建一个新的Dish,并将其与用户和类别相关联。因为我只有用户ID,但是没有访问UserManager的权限,所以我要这样做:

// ... var category = await categoryRepository.FindByUserAndCode(userId, "ABC"); // this is a category that is guaranteed to exist var dish = new Dish(); dish.UserId = userId; // notice there's no dish.User assignment, because I don't have an ApplicationUser object dish.Category = category; dishRepository.Upsert(dish); (which internally either creates a new entity or updates the existing one as appropriate)

并且这都是崩溃的原因,因为它说已经存在一个我要插入的具有相同ID的类别,所以我正在尝试复制一个主键。

由于该用户具有代码ABC的类别存在于数据库中,所以我认为这很奇怪。

这是东西:存储库返回的Category实例确实具有填充的UserId属性,但User属性是null

我认为这是导致我的问题的原因:EF可能会看到该属性为null,并且将该对象视为一个新对象。

我不知道为什么会出现null(甚至对于其他所有都具有引用用户属性的实体也是如此),但是我试图回溯,并且我想不仅仅使用用户ID,尝试让Hangfire实例化向其注入JobUserManager<ApplicationUser>,因此至少我可以通过其ID获取用户的实例。

值得注意的是,这在项目A的其他部分中也有效,只是当我执行后台作业时,发生了严重的错误,我无法终生弄清楚它是什么。

然而,UserManager的依赖关系很多,我担心我可能吠叫了错误的树,或者完全把它做错了。

我说我正在使用Hangfire的事实可能并不重要,因为它的运行假设是:只要给我您的班级名称,我就会实例化它。[[只要

依赖项已注册。

任何人以前都做过这件事,可以帮助我们了解一些情况吗?

c# entity-framework-core asp.net-core-2.2 hangfire
1个回答
0
投票
这通常是由于尝试使用分离实体作为关系而引起的,即:

dish.Category = category;

如果category与上下文分离,则EF将由于此分配而尝试创建它,并且由于它已经存在,因此创建失败。我们看不到categoryRepository.FindByUserAndCode中发生了什么,但是我想您是在查询中调用AsNoTracking,还是自己手动创建Category实例。无论哪种情况,该实例都将从上下文中分离出来。要再次附加它,只需执行以下操作:

context.Attach(category);

但是,您在这里没有直接访问您的上下文的权限。这是

您永远不要在EF中使用存储库模式
的又一个原因。不好的建议或错误地尝试按照过去的习惯做事,给开发人员带来了如此多的痛苦。

EF是ORM(对象关系映射器),这是一种说法,它是自身

数据层。 DbContext是工作单元,每个DbSet已经是一个存储库...。存储库模式用于抽象low-level数据库访问(例如,构造SQL字符串的所有步骤)。 EF已经是一个高级抽象,试图将其塞入另一个存储库模式层只会破坏它,并导致类似您在此处遇到的问题。

长而短,问题在于category已分离。您需要确保一开始它永远不会分离(例如,不要使用AsNoTracking),或者找到一种方法来确保以后重新连接它。但是,您最好的选择是完全丢弃所有存储库垃圾,而直接使用上下文。选择使用像EF这样的ORM只是选择使用第三方DAL,而不是自己编写。无论如何,在此之上编写自己的代码是错误的。您使用ASP.NET Core中的内置路由框架。您使用内置的模板引擎(即Razor)。您是否觉得有必要对它们进行一些抽象化?当然不是,那么DAL为什么有什么不同?如果仅必须创建一个抽象,则使用有意义的抽象,例如CQRS,服务层或微服务模式。

© www.soinside.com 2019 - 2024. All rights reserved.