在 Mvc 4 中使用每类型表继承将对象添加到数据库

本文关键字:继承 对象 添加 数据库 类型 Mvc | 更新日期: 2023-09-27 17:56:37

我有一个类Landlord,它使用每类型表继承从UserProfile继承。

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

这是我的帐户控制器/注册方法:

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<Tenant>();并将其保存到数据库中(使用正确的用户配置文件ID作为PK)。

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

如何避免这种情况?

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

在 Mvc 4 中使用每类型表继承将对象添加到数据库

与其分别调用WebSecurity.CreateUserAndAccount()并创建 UserProfile 子类 Tenent 或 Landlord,这会导致 UserProfile 表中出现重复条目,不如只创建子类(也提供 UserProfile 的值),然后调用方法 WebSecurity.CreateAccount()

以下是我解决问题的方法(我的子类称为医生):

在 AccountModels 中,我使用每个类型表的继承添加了子句:

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

在帐户控制器/注册方法中:

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

在这种情况下,您不会同时创建用户配置文件和租户或房东。创建实体后,无法更改实体类型(即使将其扩展到子类型)。因此,在您的情况下,您只需要跳过创建用户配置文件的步骤,只需创建并保存继承它的租户或房东实体。

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