4

I'm using EF 4.1 RC Code first. I have a many to many relation working with a composite PK in the junction table Friends. We explicitly need a separate Friends class (don't ask) which represents our junction table. Our goal is to be able to control the delete process from the User entity. Please read this before reading the rest: http://mocella.blogspot.com/2010/01/entity-framework-v4-object-graph.html. So, we managed to create our composite PK but this broke our mapping for the collection. The question is how to map FriendsCol?

public class User
{
    public int UserId { get; set; }
    public string Name { get; set; }
    public virtual ICollecion<Friends> FriendsCol { get; set; }

}

public class Friends
{
    public int User1Id { get; set; }
    public int User2Id { get; set; }

    public User User1 { get; set; }
    public User User2 { get; set; }

}

Have a composite key mapping

public class FriendsMap : EntityTypeConfiguration<Friends>
{
  HasKey(m => new { m.userId1 , m.userId2 });

  //this.HasRequired(x => x.User1)
  //.WithMany()
  //.HasForeignKey(x => x.User1Id)
  //.WillCascadeOnDelete(false);

  //this.HasRequired(x => x.User2)
  //    .WithMany()
  //    .HasForeignKey(x => x.User2Id)
  //    .WillCascadeOnDelete(false);
}

public class UserMap : EntityTypeConfiguration<UserNew>
{
  public UserMap()            
  {
    ToTable("users");
    Property(user => user.Name).HasColumnName("name");
    // HasMany<Friends>(user => user.FriendsCol).WithMany();

  }
}

3 Answers 3

1

What about this:

public class FriendsMap : EntityTypeConfiguration<Friends>
{
  HasKey(m => new { m.userId1 , m.userId2 });

  this.HasRequired(x => x.User1)
      .WithMany()
      .HasForeignKey(x => x.User1Id)
      .WillCascadeOnDelete(false);

  this.HasRequired(x => x.User2)
      .WithMany(u => u.FriendsCol)
      .HasForeignKey(x => x.User2Id)
      .WillCascadeOnDelete(false);
}

public class UserMap : EntityTypeConfiguration<UserNew>
{
  public UserMap()            
  {
    ToTable("users");
    Property(user => user.Name).HasColumnName("name");
  }
}

Edit:

I just made very simple example and it works without any problem:

class Program
{
    static void Main(string[] args)
    {
         using (var context = new Context())
         {
             context.Database.Delete();
             context.Database.CreateIfNotExists();

             var u1 = new User() { Name = "A" };
             var u2 = new User() { Name = "B" };
             var u3 = new User() { Name = "C" };

             var f1 = new Friends() { User1 = u1, User2 = u2};
             var f2 = new Friends() { User1 = u1, User2 = u3 };

             context.Friends.Add(f1);
             context.Friends.Add(f2);
             context.SaveChanges();
         }
    }
}

public class User
{
    public int UserId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Friends> FriendsCol { get; set; }
}

public class Friends
{
    public int User1Id { get; set; }
    public int User2Id { get; set; }

    public User User1 { get; set; }
    public User User2 { get; set; }

}

public class Context : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Friends> Friends { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Friends>()
            .HasKey(m => new { m.User1Id, m.User2Id });

        modelBuilder.Entity<Friends>()
            .HasRequired(x => x.User1)
            .WithMany()
            .HasForeignKey(x => x.User1Id)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Friends>()
            .HasRequired(x => x.User2)
            .WithMany(u => u.FriendsCol)
            .HasForeignKey(x => x.User2Id)
            .WillCascadeOnDelete(false);

    }
}
Sign up to request clarification or add additional context in comments.

10 Comments

Hi again Ladislav. We tried this earlier today and the error is: Schema specified is not valid. Errors: (23,6) : error 0040: Type Friends_User1 is not defined in namespace Blogtronix.Repository (Alias=Self). Consider our prev conversation: stackoverflow.com/questions/5391679/…
We also tried this. Then we get FK error: {"The INSERT statement conflicted with the FOREIGN KEY constraint \"Friends_User1\". The conflict occurred in database \"CoreContext\", table \"dbo.users\", column 'user_id'.\r\nThe statement has been terminated."} PS: user_id is the user PK.
Ok, I will have to try this myself, but I can't do it at work.
Edited my answer. Btw. your last error just says that you are saving relation to nonexisting user.
yes, this was the first mapping we did. It worked perfectly as you say. Then we tried to remove an item from the collection and save the User object. This action should delete the record from junction table. No success :( The main purpose of the question is connected with the link provided on the top of the page.
|
1

Ok, here is what really should happen:

class Program
    {
        static void Main(string[] args)
        {
            int id1;
            int id2;
            using (var context = new Context())
            {
                context.Database.Delete();
                context.Database.CreateIfNotExists();

                var u1 = new User() { Name = "A" };
                var u2 = new User() { Name = "B" };
                var u3 = new User() { Name = "C" };

                var f1 = new Friends() { User1 = u1, User2 = u2 };
                var f2 = new Friends() { User1 = u1, User2 = u3 };

                u1.FriendsCol.Add(f1);
                u1.FriendsCol.Add(f2);
                context.SaveChanges();

                id1 = u1.Id;
                id2 = u2.Id;
            }

            using (var context = new Context())
            {
                var u1 = context.Users.Find(id1);

                var friendsToRemove = u1.FriendsCol.Where(f => f.User2.Id == id2).ToList();
                foreach (var friend in friendsToRemove)
                {
                    u1.FriendsCol.Remove(friend);
                }

                context.SaveChanges();
            }
        }
    }

    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual ICollection<Friends> FriendsCol { get; set; }

        public User()
        {
            FriendsCol = new List<Friends>();
        }
    }

    public class Friends
    {
        public int User1Id { get; set; }
        public int User2Id { get; set; }

        public User User1 { get; set; }
        public User User2 { get; set; }

    }

    public class Context : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Friends> Friends { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<Friends>()
                .HasKey(m => new { m.User1Id, m.User2Id });

            modelBuilder.Entity<Friends>()
                .HasRequired(x => x.User1)
                .WithMany()
                .HasForeignKey(x => x.User1Id);

            modelBuilder.Entity<Friends>()
                .HasRequired(x => x.User2)
                .WithMany(u => u.FriendsCol)
                .HasForeignKey(x => x.User2Id);

        }
    }

Comments

1

Here is another fail to delete related entities. And this is the error: *A relationship from the 'Order_Lines' AssociationSet is in the 'Deleted' state. Given multiplicity constraints, a corresponding 'Order_Lines_Target' must also in the 'Deleted' state.*

class Program
    {
        static void Main(string[] args)
        {
            int orderid1;
            int Lineid2;
            using (var context = new Context())
            {
                var u1 = new Order() { Name = "A" };
                var l1 = new OrderLine() { Name = "L1" };
                var l2 = new OrderLine() { Name = "L2" };

                u1.Lines.Add(l1);
                u1.Lines.Add(l2);
                context.Orders.Add(u1);
                context.SaveChanges();

                Orderid1 = u1.Id;
                Lineid2 = l2.Id;
            }

            using (var context = new Context())
            {
                var u1 = context.Orders.Find(Orderid1);
                foreach (var item in u1.Lines)
                {
                    if (item.Id == Lineid2)
                    {
                        u1.Lines.Remove(item);
                        break;
                    }
                }

                context.SaveChanges();
            }
        }
    }

    public class OrderLine
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public Order Order { get; set; }
    }

    public class Order
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual ICollection<OrderLine> Lines { get; set; }

        public Order()
        {
            Lines = new List<OrderLine>();
        }
    }

    public class Context : DbContext
    {
        public DbSet<Order> Orders { get; set; }
        public DbSet<OrderLine> OrderLiness { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Order>().HasMany<OrderLine>(o => o.Lines).WithRequired(l => l.Order);

        }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.