我是CodeFirst的新手,我正在尝试创建一个Friends Collection,以便两个用户可以在他们的Friends Collection中互相拥有。
这是我的用户类:
public class User
{
public User()
{
if (FriendCollection == null) FriendCollection = new Collection<Friend>();
}
public long ID { get; set; }
public virtual ICollection<Friend> FriendCollection { get; set; }
}
public class UserConfiguration : EntityTypeConfiguration<User>
{
public UserConfiguration()
{
HasKey(x => x.ID);
}
}
这是我的朋友班:
public class Friend
{
public Friend()
{
DateAdded = DateTime.UtcNow;
}
public long ID { get; set; }
public DateTime DateAdded { get; set; }
public long UserID { get; set; }
public virtual User User { get; set; }
}
public class FriendConfiguration : EntityTypeConfiguration<Friend>
{
public FriendConfiguration()
{
HasKey(x => x.ID);
HasRequired(x => x.User).WithMany(x => x.FriendCollection).HasForeignKey(x => x.UserID);
}
}
这是我的实体类:
public Entities()
{
Database.SetInitializer<Entities>(new DropCreateDatabaseAlways<Entities>());
}
public DbSet<User> Users { get; set; }
public DbSet<Friend> Friends { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserConfiguration());
modelBuilder.Configurations.Add(new FriendConfiguration());
base.OnModelCreating(modelBuilder);
}
}
这是我的控制台代码,理想情况下我希望实现:
using (Entities db = new Entities ())
{
var u1 = new User();
db.Users.Add(u1);
var u2 = new User();
db.Users.Add(u2);
u1.FriendCollection.Add(new Friend { User = u2 });
u2.FriendCollection.Add(new Friend { User = u1 });
try
{
var cnt = db.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
}
}
}
每当我尝试使用User对象填充Friend类时,SaveChanges会抛出错误:
违反了多重性约束。 'Entities.Friend_User'关系的'Friend_User_Target'角色具有多重性1或0..1。
如果我像这样分配给UserID:
u1.FriendCollection.Add(新朋友{UserID = u2.ID});
这允许我保存实体,但不正确!
当我单步执行代码时,我可以隔离问题,这就是我发现的内容:
b.FriendCollection.Add(new Friend { UserID = a.ID });
//Friend.UserID = 1
db.SaveChanges();
//Friend.UserID = 2 matching the b.ID
所以现在我可以回到我之前的示例和SaveChanges(),如果我将Friend.User分配给调用用户,则不会抛出错误。例如:
b.FriendCollection.Add(new Friend { User = b });
db.SaveChanges()
但是当我尝试分配不同的用户时,我得到了错误。例如:
b.FriendCollection.Add(new Friend { User = a });
db.SaveChanges()
我明白了:
违反了多重性约束。 'Entities.Friend_User'关系的'Friend_User_Target'角色具有多重性1或0..1。
有人能告诉我如何修复我的模型(使用FluentAPI),以便我可以为User.FriendCollection分配不同的用户吗?
答案 0 :(得分:0)
映射不正确,至少对于模型中关系的含义不正确。
您的映射创建了一个单一关系,两个导航属性User.FriendCollection
和Friend.User
是此单一关系的两端。您已将它们定义为反向属性。
但这意味着,如果您的用户UserA在FriendCollection
中拥有FriendB,则FriendB中的User
必须是UserA,而不是任何其他用户。您的模型只能表示用户是他/她自己的朋友,可以这么说。因为您要将另一个用户添加到集合中,所以会出现异常。
在我看来,实体Friend
并不代表朋友=另一个用户,但它实际上表达了一种关系。它是用户之间多对多关系的中间实体,这种关系是Friendship
(我更喜欢这样称呼它。)
无论如何,您的模型需要两种关系。您可以保留实体,但使用此映射:
public class UserConfiguration : EntityTypeConfiguration<User>
{
public UserConfiguration()
{
HasKey(x => x.ID);
HasMany(x => x.FriendCollection)
.WithRequired();
}
}
public class FriendConfiguration : EntityTypeConfiguration<Friend>
{
public FriendConfiguration()
{
HasKey(x => x.ID);
HasRequired(x => x.User)
.WithMany()
.HasForeignKey(x => x.UserID)
.WillCascadeOnDelete(false);
}
}
(禁止对其中一个关系进行级联删除,以避免臭名昭着的“多级联删除路径异常”。)
请注意,您现在在Friend
表中有两个外键,第二个有UserID
,第一个映射有User_ID
。您可以通过将Map(m => m.MapKey("SomeUserID"))
添加到第一个映射来重命名默认列名。
使用此映射,您的控制台代码应该可以正常工作。