【问题标题】:Adding object to database using table-per-type inheritance in Mvc 4在 Mvc 4 中使用 table-per-type 继承将对象添加到数据库
【发布时间】:2013-01-29 20:00:35
【问题描述】:

我有一个类 Landlord,它使用 table-per-type 继承从 UserProfile 继承。

当新用户在应用程序上注册时,他们会输入一些条件并选择他们想要的帐户类型,LandlordTenant

这是我的 AccountController/Register 方法:

public ActionResult Register(RegisterModel model)
    {
        if (ModelState.IsValid)
        {
            // Attempt to register the user
            try
            {
                WebSecurity.CreateUserAndAccount(model.UserName, model.Password,
                                            new
                                            {
                                                Email = model.Email,
                                                FirstName = model.FirstName,
                                                LastName = model.LastName,
                                                AccountType = model.AccountType.ToString()
                                            },
                                            false);

                // Add user to role that corresponds with selected account type
                if (model.AccountType == AccountType.Tenant)
                {
                    try
                    {
                        Roles.AddUserToRole(model.UserName, "Tenant");

                        using (var db = new LetLordContext())
                        {
                            var tenant = db.UserProfile.Create<Tenant>();

                            tenant.TenantAge = null;
                            tenant.TenantGroupMembers = null;
                            tenant.UserId = WebSecurity.CurrentUserId;
                            tenant.UserName = model.UserName;
                            // more properties associated with tenant
                            // ...

                            db.UserProfile.Add(tenant);
                            db.SaveChanges();
                        }

                    }
                    catch (ArgumentException e)
                    {
                        ModelState.AddModelError("Unable to add user to role", e);
                    }
                }
                if (model.AccountType == AccountType.Landlord)
                {
                    try
                    {
                        Roles.AddUserToRole(model.UserName, "Landlord");

                        using (var db = new LetLordContext())
                        {
                            var landlord = db.UserProfile.Create<Landlord>();

                            // same idea as adding a tenant
                        }
                    }
                    catch (ArgumentException e)
                    {
                        ModelState.AddModelError("Unable to add user to role", e);
                    }
                }

                return RedirectToAction("Confirm", "Home");
            }
            catch (MembershipCreateUserException e)
            {
                ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
            }
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

例如,如果我在注册时选择 Tenant 作为所需的帐户类型,WebSecurity.CreateUserAndAccount 将正确地将用户添加到 UserProfile 表中,例如 UserProfileId 为 1。

然后,if (model.AccountType == AccountType.Tenant) 将看到所选帐户类型为 Tenant,将用户添加到该角色,UserProfileId 为 1,RoleId 为 1。在此 if-statement 中,因为已选择角色是Tenant,我创建了一个新的Tenant,如下所示:var tenant = db.UserProfile.Create&lt;Tenant&gt;();,并将其保存到数据库中(使用正确的 UserProfileID 作为 PK)。

问题: 每次我尝试注册一个用户时,都会将两个 UserProfile 实体(两行)添加到 UserProfile 表中。我知道这可能是因为我正在调用 WebSecurity.CreateUserAndAccount 并且我正在创建一个新的 Tenant 对象。

如何避免这种情况?

如何将WebSecurity.CreateUserAndAccount 中使用的模型一次添加到UserProfile 表和Tenant 表中?

【问题讨论】:

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


    【解决方案1】:

    您可以只创建子类(同时提供 UserProfile 的值),然后调用方法WebSecurity.CreateAccount().

    这是我解决问题的方法(我的子类称为医师):

    在 AccountModels 中,我使用 table-per-type 继承添加了 sublass:

    public class UsersContext : DbContext
    {
        public UsersContext()
            : base("DefaultConnection")
        {
        }
    
        public DbSet<UserProfile> UserProfiles { get; set; }
        public DbSet<Physician> Physicians { get; set; }
    }
    
    [Table("UserProfile")]
    public class UserProfile
    {
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int UserId { get; set; }
        public string UserName { get; set; }
    }
    
    [Table("Physicians")]
    public class Physician : UserProfile
    {
        public Guid PhysicianGUID { get; set; }
        public string Name { get; set; }
    }
    

    在 AccountController/Register 方法中:

    if (ModelState.IsValid)
            {
                // Attempt to register the user
                try
                {
                    using( UsersContext dbContext = new UsersContext()){
                        dbContext.Physicians.Add(new Physician { UserName = model.UserName, Name = "testDoctor", PhysicianGUID = Guid.NewGuid() });
                        dbContext.SaveChanges();
                    }
                    WebSecurity.CreateAccount(model.UserName, model.Password);
                    WebSecurity.Login(model.UserName, model.Password);
                    return RedirectToAction("Index", "Home");
                }
                catch (MembershipCreateUserException e)
                {
                    ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
                }
            }
    

    【讨论】:

      【解决方案2】:

      在这种情况下,您不会同时创建 UserProfile 和租户或房东。一旦创建了实体,实体类型就无法更改(甚至无法将其扩展为子类型)。因此,在您的情况下,您只需跳过创建 UserProfile 的步骤,只需创建并保存继承它的租户或房东实体。

      更多信息链接自我对此问题的答案的选项 1:Code First TPT Inheritance - How can I supply the foreign key instead of EF creating the parent row for me?

      【讨论】:

      • 这停止了将重复行添加到 UserProfile 表中的问题,但是现在没有条目被添加到 pages_Membership 表中,我想那是因为我刚才所做的就是注释掉了 WebSecurity.CreateUserAndAccount。正确的方法是检查选择了哪种帐户类型,然后在此基础上创建租户或房东并在该检查中调用 WebSecurity.CreateUserAndAccount?
      • 你是对的,为什么他们没有被添加到会员表中。你能让它接受一个 UserProfile 类型的对象并传入你的租户或房东吗?我在 Membership 方面工作不多,所以我不想推荐超出我深度的解决方案。从 EF 的角度来看,任何让您首先创建和保存 UserProfile 的操作都将解决您的问题。 WebSecurity.CreateUserAndAccount 是你覆盖的东西吗?
      • 我尝试覆盖 WebSecurity.CreateUserAndAccount,但它是一种抽象方法,因此我无法添加/删除参数。我已经扩展了 Mvc 4 Internet 模板附带的默认 UserProfile/Register 模型 - 注册帐户时,使用(我认为)匿名类/方法(请参阅问题)添加其他属性 - 它们来自 RegisterModel 类.如果我要创建一个 RegisterTenantModel 和 RegisterLandlordModel,请检查用户选择了哪种类型的帐户,然后根据是否可行的检查将这两个模型之一传入 - 我会尝试一下。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-28
      • 1970-01-01
      • 1970-01-01
      • 2013-04-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多