实体框架每个类型的表继承 - 将继承的类型添加到数据库,给出错误“无效的列名”

时间:2013-01-30 16:45:27

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

我已经有一段时间了,我真的无法理解。我正在使用EF5,Mvc 4,每个类型的表继承。

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

我试图实现上述using this method,但这导致了该问题中描述的问题。

我现在创建了一个RegisterTenantModel类,其属性映射到Tenant,我将一个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 name中的每个列名称收到错误t= new Tenant

有没有人曾经做过类似的事情?我是以正确的方式接近这个吗?非常感谢帮助。

修改

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

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

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

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

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

我认为解决方案是创建一个新表,并在其上指向WebSecurity.InitializeDatabaseConnection()

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

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

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

这可能就这么简单吗?

编辑

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

Entity Framework 5 Invalid Column Name error

答案 3 :(得分:0)

解决方案

  1. 确保所有派生类显式映射到表。两种简单的方法是:
    1. TableAttribute类属性:[Table("Tenant")]
    2. ToTable Fluent 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>();
      }
      
  5. 解释

    如错误消息所示,Entity Framework似乎在“derived”表中查找“base”表的列。这表明它正在尝试使用“每个混凝土类型表”(TPC)继承而不是“每种类型的表”(TPT)。

    使实体框架使用TPT非常繁琐。如果您非常仔细学习the example implementation at Inheritance with EF Code First: Part 2 – Table per Type (TPT),您可能会发现自己缺少的内容。 The follow-up article, Inheritance with EF Code First: Part 3 – Table per Concrete Type (TPC),总结了所需的配置如下:

      

    如您所见,我们使用其Requires方法来自定义TPH。我们还使用其ToTable方法创建了TPT,现在我们使用其MapInheritedPropertiesToTable方法来创建我们的TPC映射。

    我的实验表明上述摘要过于简单。似乎一个看似无关的小配置差异可能会导致使用意外的继承策略。