任何人都可以告诉我如何修复我的模型(使用Fluent API),以便我可以为User.Friend Collection分配不同的用户?

时间:2012-03-14 21:37:17

标签: entity-framework ef-code-first code-first entity-framework-5

我是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分配不同的用户吗?

1 个答案:

答案 0 :(得分:0)

映射不正确,至少对于模型中关系的含义不正确。

您的映射创建了一个单一关系,两个导航属性User.FriendCollectionFriend.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"))添加到第一个映射来重命名默认列名。

使用此映射,您的控制台代码应该可以正常工作。