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



我正在使用ASP.NET MVC应用程序,该应用程序基于NuGet提供的Identity示例。正因为如此,我已经有了一些类来处理数据库,例如ApplicationDbContext。

比如说,我决定让用户向管理员留下请求。我已经将Request类添加到模型中:

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

由于该示例使用不同的管理器来处理用户、角色等,我决定在Identity.config文件中创建另一个名为ApplicationRequestManager的管理器(尽管我不确定这是否是一个好的做法)。

 public class ApplicationRequestManager : IRequestManager
{
    private ApplicationDbContext db = new ApplicationDbContext();
    public void Add(Request request)
    {
            db.Requests.Add(request);
            db.SaveChanges();            
    }
    ...
}

这个类使用ApplicationDbContext来处理数据库,并有一些方法来创建请求、查找请求等等

我创建了一个负责在Manage控制器内发送请求的方法:

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

当调用此方法时,我得到以下异常:

实体对象不能被IEntityChangeTracker 的多个实例引用

如果我理解正确的话,异常的原因是我使用一个ApplicationDbContext通过UserManager获取User,并使用另一个ApplicationDbContext通过RequestManager添加请求,因此我的请求附加到两个上下文。据我所知,通过向UserManager和RequestManager传递相同的上下文可以避免这种错误。然而,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);

我怎样才能让我自己的经理也遵循这种模式呢?我试过使用CreatePerOwinContext方法,比如

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

我还尝试按照RoleManager示例实现Create方法

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

但我没有任何商店可以满足我的请求,所以我不知道该如何处理"新劳力士商店"部分。我该如何解决那个问题?

更新:

我试过格特的解决方案,它奏效了:

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
                  };

我还厌倦了使用HttpConext.Current.GetOwinContext().Get方法的另一种方法。我在ApplicationRequestMananger中添加了以下行:

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

它与最初的Request类配合得很好。

问题是,每种方式都有哪些优点和缺点?我读过关于外键的书,我对它的大意理解得很好;但我真的不明白"HttpContext.Current.GetOwinContext().Get()"会导致什么问题。我应该使用它吗,因为它比添加外键更简单?

设计的问题在于每个管理器都有自己的上下文。看到这个例子,我想每个经理都应该打电话。。。

db = context.Get<ApplicationDbContext>();

或者在它们的构造函数中接收请求绑定上下文。

除此之外,您还可以通过将外部字段暴露给ApplicationUserApplicationUserId?)作为Request:中的基元属性来简化此操作

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; }
}

然后像这样创建Request

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

这被称为外键关联,而不是只有引用导航属性的独立关联

相关内容

  • 没有找到相关文章

最新更新