我已经有一段时间了,我真的无法理解。我正在使用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()
。
答案 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 { ...
这可能就这么简单吗?
编辑
快速搜索还建议将实体中的字段配对,然后一次一个地添加它们以查看是否应该指责单个字段(并且它将提供指示许多失败列的错误消息)。这听起来有点让我怀疑,但可能值得一试:
答案 3 :(得分:0)
TableAttribute
类属性:[Table("Tenant")]
ToTable
Fluent API方法:ToTable("Tenant")
abstract
。MapInheritedProperties
配置方法。该方法意味着TPC。确保基本类型已注册为模型的一部分。两种简单的方法是:
将访问者属性添加到DbContext
的子类:
public DbSet<UserProfile> Users { get; set; }
覆盖OnModelCreating
子类中的DbContext
并致电DbModelBuilder.Entity
:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<UserProfile>();
}
如错误消息所示,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,现在我们使用其MapInheritedProperties
和ToTable
方法来创建我们的TPC映射。
我的实验表明上述摘要过于简单。似乎一个看似无关的小配置差异可能会导致使用意外的继承策略。