2

我已经有一段时间了,我真的无法弄清楚。我正在使用 EF5、Mvc 4、table-per-type 继承。

我有继承自 UserProfile 的租户和房东类。注册用户时选择他们想要的帐户类型,并根据此选择将他们在表单上输入的详细信息(用户名、名字、姓氏、电子邮件、帐户类型、密码)添加到 UserProfile 表中。然后,我希望将该表的 PK 作为外键添加到与他们选择的帐户类型(租户或房东)匹配的表中。

我试图使用这种方法来实现上述目的,但这导致了该问题中描述的问题。

我现在创建了一个 RegisterTenantModel 类,其属性映射到租户,并且我将 RegisterTenantModel 类型的对象传递给 AccountController/Register,如下所示......

// ...
if (tenantModel.AccountType == AccountType.Tenant)
                {
                    using (var db = new LetLordContext())
                    {
                        var t = db.UserProfile.Create<Tenant>();

                        WebSecurity.CreateUserAndAccount(tenantModel.UserName, tenantModel.Password,
                             t = new Tenant
                            {
                               AccountType = tenantModel.AccountType,
                               DateWantToRentFrom = DateTime.Now, 
                               DateWantToRentTo = DateTime.Now, 
                               DesiredPropertyLocation = "",
                               Email = tenantModel.Email, 
                               FirstName = tenantModel.FirstName,
                               UserId = WebSecurity.CurrentUserId, 
                               UserName = WebSecurity.CurrentUserName

                               // More properties that map to Tenant entity
                               // ...
                            },
                            false);

                        db.SaveChanges();

...但是现在我Invalid column namet= new Tenant.

有没有人不得不做类似的事情?我以正确的方式接近这个吗?帮助将不胜感激。

编辑

根据 Antonio Simunovic 在下面发布的内容,我想我已经意识到问题所在了。我WebSecurity.InitializeDatabaseConnection()的是这样的...

WebSecurity.InitializeDatabaseConnection("LetLordContext", "UserProfile", 
"UserId", "UserName", autoCreateTables: true);

...所以当我调用它时Websecurity.CreatUserAndAccount()AccountController/Register它会根据WebSecurity.InitializeDatabaseConnection(). 查看上面链接的问题,您会看到,根据表单上选择的帐户类型,租户或房东将通过调用...添加到 UserProfile 表中。

var tenant = db.UserProfile.Create<Tenant>();
//...
db.UserProfile.Add(tenant);
db.SaveChanges();

...导致将重复条目添加到 UserProfile 表中。

我认为解决方案是创建一个新表并指向WebSecurity.InitializeDatabaseConnection()它。

4

4 回答 4

2

您的 WebSecurity.InitializeDatabaseConnection() 方法调用是什么样的?该调用标识数据库表以存储用户数据。

WebSecurity.CreateUserAndAccount() 方法不使用上下文来存储提供的数据,它只是将第三个调用参数的对象属性名称映射到 InitializeDatabaseFile() 方法中定义的表中的列。

如果您不熟悉 SimpleMembership 机制,请查看这篇文章: http ://weblogs.asp.net/jgalloway/archive/2012/08/29/simplemembership-membership-providers-universal-providers-and-the -new-asp-net-4-5-web-forms-and-asp-net-mvc-4-templates.aspx

于 2013-01-30T19:44:44.893 回答
1

我看到了完全相同的症状,这是因为我没有将基类声明DbSet<BaseClassName>DbContext.

(违反直觉,我从不需要在我的应用程序中引用基类实体的集合,但你去吧。)

于 2015-03-25T17:09:10.927 回答
0

当我忘记用 TPT 中的表名注释子类时,我看到了这个错误。

[Table("Tenant")]
public class Tenant : UserProfile { ...

可以这么简单吗?

编辑

快速搜索还建议将实体中的字段配对并一次将它们添加回来,以查看是否应归咎于单个字段(它将提供指示许多失败列的错误消息)。这对我来说听起来有点可疑,但可能值得一试:

实体框架 5 无效的列名错误

于 2013-01-30T16:56:22.483 回答
0

解决方案

  1. 确保所有派生类都显式映射到表。两种简单的方法是:
    1. TableAttribute类属性:[Table("Tenant")]
    2. ToTable流利的API方法:ToTable("Tenant")
  2. 确保基本类型是abstract.
  3. 确保您没有为任何表调用MapInheritedProperties配置方法。该方法意味着 TPC。
  4. 确保将基本类型注册为模型的一部分。两种简单的方法是:

    1. 将访问器属性添加到您的子类DbContext

      public DbSet<UserProfile> Users { get; set; }
      
    2. OnModelCreating在您的子类中覆盖DbContext并调用DbModelBuilder.Entity

      protected override void OnModelCreating(DbModelBuilder modelBuilder)
      {
          base.OnModelCreating(modelBuilder);
          modelBuilder.Entity<UserProfile>();
      }
      

解释

如错误消息所示,Entity Framework 似乎正在“派生”表中查找“基”表的列。这表明它正在尝试使用“每个具体类型的表”(TPC)继承而不是“每个类型的表”(TPT)。

使 Entity Framework 使用 TPT 是相当繁琐的。如果您非常仔细地研究了使用 EF 代码优先继承:第 2 部分 – 每个类型的表 (TPT)中的示例实现,您可能会发现您遗漏了什么。后续文章Inheritance with EF Code First: Part 3 – Table per Concrete Type (TPC)总结了所需的配置如下:

如您目前所见,我们使用它的 Requires 方法来自定义 TPH。我们还使用它的ToTable方法来创建 TPT,现在我们正在使用它的MapInheritedPropertieswithToTable方法来创建我们的 TPC 映射。

我的实验表明,上面的总结过于简单化了。看起来,一个看似无关的配置差异可能会导致使用意外的继承策略。

于 2014-01-17T05:53:28.007 回答