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

时间:2014-10-26 17:26:35

标签: c# asp.net asp.net-mvc entity-framework asp.net-identity

我正在使用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来获取User - 通过UserManager并使用另一个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>()));
    }

但我的请求没有任何商店,所以我不知道我应该怎么做'新的RoleStore'部分。我怎么能解决这个问题?

更新

我尝试过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
                  };

我也厌倦了使用HttpConext.Current.GetOwinContext()的方法。获取方法。我已将以下行添加到ApplicationRequestMananger中:

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

它与原始的Request类一起运行良好。

问题是,每种方式有哪些优点和缺点?我读过关于外键的内容,我对这个概念很了解;但我真的不明白什么问题'HttpContext.Current.GetOwinContext()。get()'的原因。我应该使用它,因为它比添加外键更简单吗?

1 个答案:

答案 0 :(得分:2)

您的设计遇到的问题是每个经理都有自己的背景。看到this example,我认为每位经理都应该致电......

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

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