简体   繁体   English

将使用DbContext的类添加到ASP.NET Identity 2项目

[英]Adding a class which uses DbContext to ASP.NET Identity 2 project

I'm working with ASP.NET MVC application which is based on Identity sample available via NuGet . 我正在使用ASP.NET MVC应用程序,该应用程序基于可通过NuGet获得的Identity示例。 Because of this I already have some classes to work with the database eg ApplicationDbContext. 因此,我已经有了一些可与数据库一起使用的类,例如ApplicationDbContext。

Say, I decided to let users leave requests for the administrator. 说,我决定让用户将请求留给管理员。 I've added the Request class to the models: 我已经将Request类添加到模型中:

public class Request
{
    public int Id { get; set; }
    public string Message { get; set; }
    public ApplicationUser User { get; set; }
}

Since the sample uses different managers to work with users, roles, etc, I've decided to create another one called ApplicationRequestManager inside the Identity.config file (though I'm not sure it's a good practice). 由于该示例使用不同的管理器来处理用户,角色等,因此我决定在Identity.config文件中创建另一个名为ApplicationRequestManager的应用程序(尽管我不确定这是一个好习惯)。

 public class ApplicationRequestManager : IRequestManager
{

    private ApplicationDbContext db = new ApplicationDbContext();

    public void Add(Request request)
    {
            db.Requests.Add(request);
            db.SaveChanges();            
    }
    ...
}

This class uses the ApplicationDbContext to work with the database and has some methods to create a request, find it and so on. 此类使用ApplicationDbContext与数据库一起使用,并具有一些方法来创建请求,查找请求等。

I've created a method responsible for sending request inside the Manage controller: 我创建了一个方法,负责在Manage控制器内发送请求:

public ActionResult SendRequest(IndexViewModel model)
    {
        Request request = new Request { Message = model.Message, User = UserManager.FindById(User.Identity.GetUserId()) };
        requestManager.Add(request);
        return View();
    }

When this method is invoked, I get the following exception: 调用此方法时,出现以下异常:

An entity object cannot be referenced by multiple instances of IEntityChangeTracker 一个IEntityChangeTracker的多个实例不能引用一个实体对象

If I understood correctly, the reason of exception is that I use one ApplicationDbContext to get User - via UserManager and I use another ApplicationDbContext to add the request - via RequestManager, so my request is attached to two contexts. 如果我正确理解,则出现异常的原因是,我使用一个ApplicationDbContext通过UserManager获取用户,而我使用另一个ApplicationDbContext通过RequestManager添加请求,因此我的请求附加到两个上下文。 As far as I know, such mistake can be avoided by passing the same context to both UserManager and RequestManager. 据我所知,可以通过将相同的上下文传递给UserManager和RequestManager来避免这种错误。 However, UserManager gets its context via the OwinContext together with other managers: 但是,UserManager与其他管理器一起通过OwinContext获取其上下文:

// Configure the db context, user manager and role manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
        app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

How can I make my own manager follow that pattern as well? 如何使自己的经理也遵循这种模式? I've tried to use the CreatePerOwinContext method like 我试图使用像CreatePerOwinContext方法

 app.CreatePerOwinContext<ApplicationRequestManager>(ApplicationRequestManager.Create);

And I've also tried to implement the Create method following the RoleManager example 而且我还尝试按照RoleManager示例实现Create方法

public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
    {
        return new ApplicationRoleManager(new RoleStore<ApplicationRole>(context.Get<ApplicationDbContext>()));
    }

But I don't have any Store for my requests so I don't know what I should do with the 'new RoleStore' part. 但是我没有任何商店可以满足我的要求,所以我不知道应该对“新RoleStore”部分做什么。 How could I solve that problem? 我该如何解决这个问题?

Updated: 更新:

I've tried Gert's solution and it worked: 我已经尝试过Gert的解决方案,它的工作原理是:

public class Request
{
  public int Id { get; set; }
  public string Message { get; set; }

  [ForeignKey("User")]
  public int ApplicationUserId { get; set; }
  public ApplicationUser User { get; set; }
}

var userId = User.Identity.GetUserId();
Request request = new Request
                  { 
                      Message = model.Message,
                      ApplicationUserId = userId
                  };

I've also tired another way using HttpConext.Current.GetOwinContext().Get method. 我还用HttpConext.Current.GetOwinContext()。Get方法的另一种方式。 I've added the following line to my ApplicationRequestMananger: 我在ApplicationRequestMananger中添加了以下行:

public ApplicationRequestManager()
    {
        this.db = HttpContext.Current.GetOwinContext().Get<ApplicationDbContext>();
    }

And it worked fine with the original Request class. 并且它与原始Request类一起正常工作。

The question is, what advantages and disadvantages does each way have? 问题是,每种方式都有哪些优点和缺点? I've read about foreign keys and I understand the general idea quite well; 我已经阅读了有关外键的信息,并且我对一般概念非常了解。 but I don't really understand what problems can 'HttpContext.Current.GetOwinContext().Get()' cause. 但我不太了解HttpContext.Current.GetOwinContext()。Get()会导致什么问题。 Should I use it since it's simpler than adding foreign keys? 我应该使用它,因为它比添加外键更简单?

The trouble with your design is that each manager has its own context. 设计的麻烦在于每个经理都有自己的环境。 Seeing this example , I think each manager should call... 这个例子 ,我想每个经理都应该打电话给...

db = context.Get<ApplicationDbContext>();

...or receive the request-bounded context in their constructor. ...或在其构造函数中接收受请求限制的上下文。

Apart from that, you could make this much simpler by exposing the foreign field to ApplicationUser ( ApplicationUserId ?) as a primitive property in Request : 除此之外,您可以通过将外部字段作为Request的原始属性暴露给ApplicationUserApplicationUserId ?)来简化此过程:

public class Request
{
    public int Id { get; set; }
    public string Message { get; set; }

    [ForeignKey("User")]
    public int ApplicationUserId { get; set; }
    public ApplicationUser User { get; set; }
}

And then create Request like so: 然后像这样创建Request

    var userId = User.Identity.GetUserId();
    Request request = new Request
                      { 
                          Message = model.Message,
                          ApplicationUserId = userId
                      };

This is refered to as foreign key associations , as opposed to independent associations that only have a reference navigation property. 仅具有参考导航属性的独立关联相反,这称为外键关联

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM