2

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

当新用户在应用程序上注册时,他们输入一些条件并选择他们想要的帐户类型,或者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表中,例如 aUserProfileId为 1。

然后,if (model.AccountType == AccountType.Tenant)会看到选定的帐户类型是Tenant,将用户添加到该角色,aUserProfileId为 1,aRoleId为 1。在此范围内if-statement,因为选定的角色是Tenant,所以我像这样创建一个新的Tenantvar tenant = db.UserProfile.Create<Tenant>();并将其保存到数据库中(使用正确的 UserProfileID 作为 PK)。

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

我该如何避免这种情况?

如何将正在使用的模型添加WebSecurity.CreateUserAndAccountUserProfile表和Tenant表 ONCE 中?

4

2 回答 2

2

无需分别调用WebSecurity.CreateUserAndAccount()和创建 UserProfile 子类 Tenent 或 Landlord,这会导致 UserProfile 表中出现重复条目​​,您只需创建子类(同时提供 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));
            }
        }
于 2013-03-22T11:17:58.133 回答
1

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

更多信息链接自我对这个问题的回答的选项 1:代码优先 TPT 继承 - 如何提供外键而不是 EF 为我创建父行?

于 2013-01-29T20:21:13.850 回答