27

I am just getting started with EF and I watched some great tutorial videos. I am stuck with the following.

I have a class for a collection of files, I would like these to be tied to events and/or people

public class file{
    public int id {get;set;}
    public string path {get;set;}
}

public event {
    public int id {get;set;}
    public string eventname {get;set}
    public virtual ICollection<file> files {get;set;}
    public event(){ files = new list<file>();}
}

public person {
    public int id {get;set;}
    public string name {get;set}
    public virtual ICollection<file> files {get;set;}
    public person(){ files = new list<file>();}
}

Now when I generate the database my file table has a PersonID AND EventID.

I want to be able to let users attach files to people and/or events.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Code Noob
  • 271
  • 1
  • 3
  • 3
  • Now that the DB and Object Model are all set, any suggestions to how I should approach the controllers and view to add a new Person and allow the user to upload a file and make the necessary relationship between files and people? –  Nov 24 '10 at 16:46

1 Answers1

32

What you are getting is the default behavior of EF Code First in terms of mapping a 1 to Many association to the database. For example you have a ICollection<File> on Person class, as a result, EF will create a FK on Files table (PersonId) and map it to Id PK on Persons table.

Now, my guess is that you like to have a many to many relationship between File and Person, so that each file can relates to many Persons and each Person can have many files (same story for Event object as well). One way to achieve this is to put navigation properties on File class pointing to Event and Person classes. So, your model should be changed to this:

public class File {
    public int Id { get; set; }
    public string Path { get; set; }
    public virtual ICollection<Event> Events { get; set; }
    public virtual ICollection<Person> Persons { get; set; }
}

public class Event {
    public int Id { get; set; }
    public string EventName { get; set; }
    public virtual ICollection<File> Files {get;set;}
}

public class Person {
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<File> Files { get; set; }
}

public class MyContext : DbContext {
    public DbSet<Person> Persons { get; set; }
    public DbSet<Event> Events { get; set; }
    public DbSet<File> Files { get; set; }
}

As a result, EF will create link tables (Events_Files and Files_Persons) to map these many to many associations to the database.

Update:
When using POCOs with EF, if you mark your navigation properties as virtual you will opt-in to some of the additional EF supports like Lazy Loading and Relationship Fixup. So in general have a virtual keyword in navigation properties considered to be a good practice.

Morteza Manavi
  • 33,026
  • 6
  • 100
  • 83
  • I'm pretty sure for the link table (File class), it should be "public virtual Events" instead of ICollection. Btw, I knew about navigation properties, but didn't know about the virtual keyword. Good tip. Thx. – Sleeper Smith Mar 17 '11 at 04:29
  • 1
    When using the example above, creating a new relation also adds a new item in the related table. So in this case you have File and do the following: File.Events = new Eventlist (where eventlist is populated with events retrieved from the database) the db.savechanges adds not only the relationship record in Events_Files but also an event in Events table. What should be a proper way to add a relationship record in events_files but not an extra record in events. – Mounhim Feb 14 '12 at 15:19
  • @Mounhim you should ask that as a separate question. But in the meantime, I think you could try with `MyContext.Events.Attach(...)` – Charles Prakash Dasari Dec 21 '14 at 10:30