locked
How to create a 2:1 or n:1 relationship using Code-First in the Entity Framework 4 CTP RRS feed

  • General discussion

  • Hello,

    I'm just curious, let's say I'm making a supposed 'community' software, and I want the users to have two boards assigned to them, but no more than two.

    Given that I'm using two differently named properties (PublicBoardId and PrivateBoardId, which have respective PrivateBoard and PublicBoard properties of the appropriate type), which refer to the BoardId of the boards within the respective board table, how do I properly ensure this relationship works using a Code-First methodology?  For the sake of a cross-reference, the user-based boards refer to the user, this seems to be where issues arise.  Removing the specific dependency of a 2:1 relationship where the user refers to user-ignorant boards, it works, but when I refer to the variation that is user-aware, I receive errors akin to: "Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values."

    Edit:

    This is confusing to me because if I use a many to one relationship where the number of 'boards' to the user is unbounded, it works, even when the user-based boards refer to the user directly.  I'm confused as to why this is.

    Mind you I'm new to the EF, so a lot of how it works is foreign to me.

    Thanks,

    -Alexander Morou

    Edit 2:

    In the OnModelCreating of the DbContext, I have tried the following, but afterwards I get that the property PublicBoard has been explicitly excluded O_o;

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MessageBoard>().ToTable("Boards");
        modelBuilder.Entity<CommunityBoard>().ToTable("CommunityBoards");
        var userBoards = modelBuilder.Entity<UserMessageBoard>();
        userBoards.ToTable("UserBoards");
        var registeredUsers = modelBuilder.Entity<RegisteredUser>();
        registeredUsers.Map(p => {
            p.ToTable("Users");
            p.Properties(q => new { UserId = q.UserId, q.PublicBoard, q.PrivateBoard });
        });
        base.OnModelCreating(modelBuilder);
    }
    
    

    Which seems counter intuitive.

    After reversing the order in the Anonymous type provided, the q.PublicBoard being after q.PrivateBoard, I get that PrivateBoard is explicitly excluded, which implies that a n:1 mapping is illegal in the present form of the Entity Framework.  Can someone verify or suggest an alternative?

    Friday, March 18, 2011 3:26 PM

All replies

  • Hello Alexander,

     

    Welcome to the EF Forum!

    According to your description, if you would like to know how to create one to many relationship in EF4, I could show you an example.

    Here it is:

    public class Place
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int? ParentId { get; set; }
        public Place Parent { get; set; }
    }

    public class Institute
    {
        [DatabaseGenerated(DatabaseGenerationOption.None)]
        public int Id { get; set; }
        public string Name { get; set; }

        public int? PlaceId { get; set; }
        public Place Place { get; set; }
    }

    public class Context : DbContext
    {
        public DbSet<Place> Places { get; set; }
        public DbSet<Institute> Institutes { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Institute>().Map(mc =>
            {
                mc.Properties(p => new { p.Id, p.Name });
                mc.ToTable("Institutes");
            })
            .Map(mc =>
            {
                mc.Properties(p => new { p.Id, p.PlaceId });
                mc.ToTable("InstitutePlaces");
            });

            modelBuilder.Entity<Place>()
                        .HasOptional(p => p.Parent)
                        .WithMany()
                        .HasForeignKey(p => p.ParentId);
        }
    }
    I hope this can help you.

     

    have a nice day,


    Jackie Sun [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, March 22, 2011 6:38 AM
  • Jackie Sun,

    I ended up figuring out that the relationship I was trying to build was probably a bad one, so the example above made me think of another topic I posted (close enough that I thought I was in that thread for a bit ;), and hoped you might be able to help.  The topic is: Introducing FOREIGN KEY constraint 'Constraint on PROPERTY' on table 'TABLE' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION

    The main issue I have with what you posted is the focus of what I want to do.  I ran your example, and after fixing a few naming errors (ModelBuilder was DbModelBuilder, DatabaseGenerationOption was DatabaseGeneratedOption), I added some test data and saved it to the database.  Afterwords I tried to delete the first place created from the relationships and received the following error:

    A problem occurred attempting to delete row 1.
    Error Source: .Net SqlClient Data Provider.
    Error Message: The DELETE statement conflicted with the REFERENCE constraint "Institute_Place1".  The conflict occurred in database "ContextTest.Models.TestContext", table "dbo.InstitutePlaces", column 'PlaceId'.

    The issue I'm having is I want to setup a relational set such that when the place was deleted, it would properly delete the appropriate rows in other tables.

    Here's a link to the source of the project I'm working on, as it is the methods I'm using work in doing what I want, but I wonder if the relationships could be setup such that when I delete a user it properly cascades to the other tables and removes the entries.  If such isn't possible, I guess what I have will work.  I'm just new to the Entity Framework, MFC 3, ASP.NET and know little of SQL.

    Tuesday, March 22, 2011 9:33 AM