我的应用程序面向.NET 4.5并使用EntityFramework 5.0,Sql Server Compact 4.0。
我正在尝试使用某些实体为我的数据库播种,但它一直在抛出:
“System.Data.SqlServerCe.SqlCeException:无法插入外键值,因为不存在相应的主键值。[外键约束名称= FK_dbo.User_dbo.Account_AccountKey]”
以下是我的域名实体的简化版本:
public class Account
{
public int AccountKey { get; set; }
public string Name { get; set; }
public ICollection<User> Users { get; set; }
}
internal class AccountMap : EntityTypeConfiguration<Account>
{
public AccountMap()
{
this.HasKey(e => e.AccountKey);
this.Property(e => e.AccountKey).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(e => e.Name).IsRequired();
}
}
public class User
{
public int UserKey { get; set; }
public string Name { get; set; }
public Account Account { get; set; }
public int AccountKey { get; set; }
}
internal class UserMap : EntityTypeConfiguration<User>
{
public UserMap()
{
this.HasKey(e => e.UserKey);
this.Property(e => e.UserKey).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(e => e.Name).IsRequired();
this.HasRequired(e => e.Account)
.WithMany(e => e.Users)
.HasForeignKey(e => e.AccountKey);
}
}
public class TestContext : DbContext
{
public TestContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
public DbSet<User> Users { get; set; }
public DbSet<Account> Accounts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); modelBuilder.Conventions.Remove<StoreGeneratedIdentityKeyConvention>();
modelBuilder.LoadConfigurations();
}
}
连接字符串:
<connectionStrings>
<add name="TestContext" connectionString="Data Source=|DataDirectory|\TestDb.sdf;" providerName="System.Data.SqlServerCe.4.0" />
</connectionStrings>
这是一个展示问题的示例应用程序:
class Program
{
static void Main(string[] args)
{
try
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<TestContext>());
using (var context = new TestContext())
context.Database.Initialize(false);
for (int i = 0; i < 2; i++ )
using (var context = new TestContext())
{
var account1 = new Account()
{
Name = "Account1"
};
var user1 = new User()
{
Name = "User1",
Account = account1
};
context.Accounts.AddOrUpdate(
e => e.Name,
account1
);
context.Users.AddOrUpdate(
e => e.Name,
user1
);
context.SaveChanges();
Console.WriteLine("\nChanges saved.");
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress any key to exit...");
Console.ReadLine();
}
}
Account类与User类有一对多的关系。我的种子方法尝试使用默认用户初始化默认帐户。有人会认为这是AddOrUpdate方法的常见用法,但在这种情况下似乎不起作用。如果我只是添加相同的帐户两次,没有用户,它没有任何问题。
有谁能看出我错过了哪一点?
这种简单的关系有什么问题吗?
AddOrUpdate方法是否适用于这种情况?
如果没有,那么完成这种播种的正确方法是什么?
答案 0 :(得分:0)
这应该让你走上正轨:
using (var context = new TestContext())
{
// with 1:many we don't need to specify PK when seeding, EF will pick this up
var accounts = new List<Account>
{
// new a list of type User for each account
new Account() { Name = "Account1", Users = new List<User>() },
new Account() { Name = "Account2", Users = new List<User>() }
};
accounts.ForEach(a => context.Accounts.AddOrUpdate(a));
context.SaveChanges();
var users = new List<User>
{
// set the account key for each User
new User() { Name = "User1", AccountKey = 1 },
new User() { Name = "User2", AccountKey = 1 },
new User() { Name = "User3", AccountKey = 2 },
new User() { Name = "User4", AccountKey = 2 }
};
users.ForEach(u => context.Users.AddOrUpdate(u));
context.SaveChanges();
// add users to list of type user in an account
accounts[0].Users.Add(users[0]);
accounts[0].Users.Add(users[1]);
accounts[1].Users.Add(users[2]);
accounts[1].Users.Add(users[3]);
context.SaveChanges();
}
修改强>
在执行此操作之前,您可能希望删除并重新创建数据库,因为如果您多次播种数据库并“将同一帐户添加两次,没有用户”,则帐户表中会有多行用户表中没有。
您还可以将以下注释添加到User.Account
:
[ForeignKey("AccountKey")]
public Account Account { get; set; }
此外,您的导航属性都不是虚拟的原因是什么?
答案 1 :(得分:0)
我使用了以下修改:
var account1 = new Account()
{
Name = "Account1"
};
var user1 = new User()
{
Name = "User1",
//Account = account1
};
account1.Users = new List<User>(new[]{user1});
context.Accounts.AddOrUpdate(
e => e.Name,
account1
);
context.SaveChanges();
然而,我不知道为什么会这样。我仍然认为第一次尝试是有道理的,应该没有任何问题。