I have little experience with the Entity Framework. I am trying to use the Eager Loading but it seems that I am doing something wrong.
Although I am using the "include" in my query, the navigation property "Subjects" of the Department class, is not loading.
Below you can find the 2 POCO, DBContext and the Main method.
The output is just the title of the department ("Computer Science"), instead to display the related subjects ("Java","C#","C++").
public class Department
{
public Department()
{
Subjects = new HashSet<Subject>();
}
public int ID { get; set; }
public string Title { get; set; }
public ICollection<Subject> Subjects { get; set; }
}
public class Subject
{
public Subject()
{
aDepartment = new Department();
}
public int ID { get; set; }
public string Title { get; set; }
public int DepartmentID { get; set; }
public Department aDepartment { get; set; }
}
public class ModelDB : DbContext
{
public ModelDB() : base("name=ModelDB")
{
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = true;
}
public DbSet<Department> Departments { get; set; }
public DbSet<Subject> Subjects { get; set; }
}
static void Main(string[] args)
{
ModelDB db = new ModelDB();
/*
Department dep = new Department() { ID = 1, Title = "Computer Science" };
db.Departments.Add(dep);
db.SaveChanges();
Subject s1 = new Subject() { ID=1, Title="Java", aDepartment = dep };
db.Subjects.Add(s1);
db.SaveChanges();
Subject s2 = new Subject() { ID = 2, Title = "C#", aDepartment = dep };
db.Subjects.Add(s2);
db.SaveChanges();
Subject s3 = new Subject() { ID = 3, Title = "C++", aDepartment=dep };
db.Subjects.Add(s3);
db.SaveChanges();
*/
var lstDepartments = db.Departments.Include("Subjects");
foreach (var d in lstDepartments)
{
Console.WriteLine(d.Title);
var ss = d.Subjects;
foreach(var s in ss)
{
Console.WriteLine(s.Title);
}
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
The main issue is that you are initializing the reference navigation property (aDepartment = new Department();) which is confusing the EF infrastructure and prevents it working properly. Initializing collection navigation properties is ok (although not mandatory), but never do that for reference navigation properties.
Removing the above line from the Subject constructor will fix the issue. Additionally, although it somehow works in your case (surprisingly to me), better follow the naming conventions and don't call navigation property aDepartment, but simply Department to line up with the DepartmentID FK property.
Here is the corrected working version of the Subject entity:
public class Subject
{
public int ID { get; set; }
public string Title { get; set; }
public int DepartmentID { get; set; }
public Department Department { get; set; }
}
I feel like you might not have told EF what the foreign keys are. Where is the mapping class that is telling EF this link? If you don't have this, please just add [ForeignKey("DepartmentID")] attribute above the Department navigation property on Subject and see if that fixes your issue, new Department or not. :)
Related
how do I insert data in many to many relationship?
I have these two models definded by this code
public class Article
{
public int ArticleID { get; set; }
public string Title { get; set; }
public DateTime Date { get; set; }
public string Anotation { get; set; }
public string Body { get; set; }
public virtual ICollection<ArticleTag> ArticleTags { get; set; }
}
public class ArticleTag
{
public int ArticleTagID { get; set; }
public string TagName { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
Now the big Q is how to seed the database with test data. I have some experience with normal tables and queries and in MVC EF I am quite a novice. Normally I would create an association table and in it define the link between these models. But I have read many tutorials and none gave me a deterministic way how to do it, so I you can imagine my confusion.
As I said before, I "created" an assoc table via ModelBuilder and that's where I end :(
public class DatabaseContext : DbContext
{
public DbSet<Article> Articles { get; set; }
public DbSet<ArticleTag> ArticleTags { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Article>().
HasMany(at => at.ArticleTags).WithMany(a => a.Articles).
Map(m => m.MapLeftKey("ArticleID").MapRightKey("ArticleTagID").ToTable("Articles_To_ArticleTags"));
}
}
I need to know the easiest way to seed my DB (don't care if have to delete the assoc table) and understand how it works in the MVC - linking the two models, linking two specific instances, ... , and how to code it all.
Thx for any answer.
So finally solved!
Found a good post here and with this one together I made it work.
In short what I had to do:
Remove my builder link - EF itself creates link (own assoc table)
A little modify models
Create DatabaseInitializer
In the Global.asax to the method Application_Start() add Database.SetInitializer(new DatabaseInitializer()); declaration
don't forget to se ConnectionString and DBcontext
Normally use in a View
Modifications in constructor (not sure if absolutely necessary, maybe it does the same thing as native/default constructor):
public class Article
{
public int ArticleID { get; set; }
public string Title { get; set; }
public DateTime Date { get; set; }
public string Anotation { get; set; }
public string Body { get; set; }
public string SourceLink { get; set; }
public virtual List<ArticleTag> ArticleTags { get; set; }
public Article()
{
ArticleTags = new List<ArticleTag>();
}
}
public class ArticleTag
{
public int ArticleTagID { get; set; }
public string TagName { get; set; }
public virtual List<Article> Articles { get; set; }
public ArticleTag()
{
Articles = new List<Article>();
}
}
And the DatabaseInitializer
public class DatabaseInitializer : DropCreateDatabaseIfModelChanges<DatabaseContext>
{
protected override void Seed(DatabaseContext context)
{
ArticleTag tag1= new ArticleTag { TagName = "aaaa" };
ArticleTag tag2= new ArticleTag { TagName = "bbbb" };
ArticleTag tag3= new ArticleTag { TagName = "cccc" };
var articleTags = new List<ArticleTag> { tag1, tag2, tag3};
articleTags.ForEach(i => context.ArticleTags.Add(i));
context.SaveChanges();
Article a1 = new Article
{
Title = "Title1",
Date = DateTime.Now,
Anotation = "Anotation1",
Body = "article_1",
ArticleTags = new List<ArticleTag> { tag1 }
};
Article a2 = new Article
{
Title = "Title12",
Date = DateTime.Now,
Anotation = "Anotation2",
Body = "article_2",
ArticleTags = new List<ArticleTag> { tag2, tag3 }
};
var articles = new List<Article> { a1, a2 };
articles.ForEach(a => context.Articles.Add(a));
context.SaveChanges();
}
}
I can't wrap my mind around this issue and haven't found the correct search keys yet:
I would like to have several categories of items in which all items have specific attributes. Those attributes (text fields, dropdowns, or checkboxes) should be added to a category and I want to edit and save those attributes for each item.
I'm working with MVC 4 and code-first EF5. How can I implement this?
My first approach were several classes like Text, Dropdown that were inherited from an abstract Attribute class and a Category class like this:
public class Category
{
[Key]
public int CategoryId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Item> Items { get; set; }
public virtual ICollection<Attribute> Attributes { get; set; }
}
But then I had no idea to proceed. Am I on the right way or completely wrong? Can someone give me a few hints I can search for?
Edit
Ultimately I'm trying to build a list of hifi devices. Speakers have different attributes than amplifier and those have different attributes to tape recorders. I would like to give a unified look for the details of each device and pre-define specific attributes to that category with an additional free-for-all text area. Speaker XYZ is my item, Speaker my category and dB an attribute.
Ok so this question is basically about the data design.
First, I assume that the rule is:
One item has one category
One category has many attributes
One item has many attributes associated with the category
For rule no.1, it is good enough in your design. (simplified example)
public class Category{
public IEnumerable<Item> Items{get;set;}
}
public class Item{
public Category Category{get;set;}
}
Its clear enough.
For rule no.2, I think you should make a CategoryAttribute class. It holds the relation between one to many Category and Attribute. Basically, CategoryAttribute is a master, whereas the children will be ItemAttribute.
public class Category{
public IEnumerable<CategoryAttribute> CategoryAttributes{get;set;}
}
public class CategoryAttribute{
public Category Category{get;set;}
public string CategoryName{get;set;}
public string DefaultValue{get;set;} // maybe a default value for specific
// attribute, but it's up to you
public IEnumerable<ItemAttribute> ItemAttributes{get;set;}
}
The IEnumerable<ItemAttribute> is the one to many relation between category attribute and item attribute.
For rule no.3, the the ItemAttribute described in rule no.2 will be represented attribute owned by each item.
public class Item{
public IEnumerable<ItemAttribute> ItemAttributes{get;set;}
}
public class ItemAttribute{
public Item Item {get;set;} // it owned by one attribute
public CategoryAttribute{get;set;} // it owned by one category attribute
}
I don't quite sure about how to represent relation or primary and foreign key in code first. Hopefully I can enhance my answer if needed (and if I able). But hopefully my illustration about relations and the class designs for each objects.
I think something like this may work for you...
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Item> Items { get; set; }
public virtual ICollection<Attribute> Attributes { get; set; }
}
public class Item
{
public int ItemId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
public virtual ICollection<ItemAttribute> ItemAttributes { get; set; }
}
public class Attribute
{
public int AttributeId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<ItemAttribute> ItemAttributes { get; set; }
}
public class ItemAttribute
{
public int ItemId { get; set; }
public int AttributeId { get; set; }
public Item Item { get; set; }
public Attribute Attribute { get; set; }
public string Value { get; set; }
public int ValueInt{ get; set; }
// etc.
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ItemAttribute>()
.HasKey(x => new { x.ItemId, x.AttributeId });
modelBuilder.Entity<ItemAttribute>()
.HasRequired(x => x.Item)
.WithMany(x => x.ItemAttributes)
.HasForeignKey(x => x.ItemId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<ItemAttribute>()
.HasRequired(x => x.Attribute)
.WithMany(x => x.ItemAttributes)
.HasForeignKey(x => x.AttributeId)
.WillCascadeOnDelete(false);
// AttributeCategories is created for you - but you can do the same as ^ above to customize
// just change 'ICollection<Category> Categories' to collection of 'ItemAttribute'
}
// use it like e.g.
var item = new Item { Name = "ItemTest", };
var attribute = new Attribute { Name = "attributeTest", };
item.ItemAttributes = new List<ItemAttribute>
{
new ItemAttribute { Item = item, Attribute = attribute, Value = "test", },
};
var category = new Category
{
Name = "cat1",
Items = new[]
{
item,
new Item{ Name = "Item1", },
new Item{ Name = "Item2", },
new Item{ Name = "Item3", },
new Item{ Name = "Item4", },
new Item{ Name = "Item5", },
},
Attributes = new[]
{
attribute,
new Attribute{ Name = "att1", },
new Attribute{ Name = "att2", },
}
};
db.Categories.Add(category);
db.SaveChanges();
var categories = db.Categories.ToList();
ItemAttribute is used to connect and store values.
And you're going to need to further adjust as per your requirements.
I actually never worked with code first approach, but I can give you some idea about how this scenario can be handled...To me, it looks that Item is the major one instead of Category. So you can have this structure...
public class Category
{
[Key]
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public string CategoryDescription { get; set; }
// use attributes here if you want them for Category
//public Dictionary<string, string> ItemnAttributes { get; set; }
}
public class MyItem
{
[Key]
public int ItemId { get; set; }
public string ItemName { get; set; }
public string ItemDescription { get; set; }
public Category ItemnCatagory { get; set; }
public Dictionary<string, string> ItemnAttributes { get; set; }
}
Hope this helps..
I've built my Domain model layer, my repository layer, and now I'm working on my DTO layer to be used by a webApi project. I'm in the middle of implementing an Update service method, and I'm wondering about partial updates. Here's my DTO class:
public class FullPersonDto
{
public FullPersonDto()
{
Friends = new List<Person>();
}
public FullPersonDto(Person person)
{
PersonId = person.PersonId;
DateCreated = person.DateCreated;
Details = person.Details;
Friends = new List<Person>();
foreach (Person friend in person.Friends)
{
Friends.Add(new PersonDto(friend));
}
}
[Key]
public int PersonId { get; set; }
[Required]
public virtual DateTime DateCreated { get; set; }
public virtual string Details { get; set; }
public List<Person> Friends { get; set; }
public Person ToEntity()
{
var person = new Person
{
PersonId = PersonId,
DateCreated = (DateTime) DateCreated,
Details = Details,
Friends = new List<Person>()
};
foreach (PersonDto friend in Friends)
{
person.Friends.Add(friend.ToEntity());
}
return person;
}
}
Here's my Update method in my Repository:
public Person UpdatePerson(Person person)
{
var entry = _db.Entry(person);
if (entry.State == EntityState.Detached)
{
var dbSet = _db.Set<Person>();
Person attachedPerson = dbSet.Find(person.PersonId);
if (attachedPerson != null)
{
var attachedEntry = _db.Entry(attachedPerson);
attachedEntry.CurrentValues.SetValues(person); // what if values are null, like ID, or DateCreated?
}
else
{
entry.State = EntityState.Modified;
}
}
SaveChanges();
return person;
}
My question is: What if I only need to update the Details of a person via my webAPI? Is the convention to construct an entire PersonDto and Update the entire object using SetValues, or is there any way I can specify that I only want a single field updated so that I don't have to send a ton of data over the wire (that I don't really need)?
If it is possible to do partial updates, when is it ever good to update the entire entity? Even if I have to update 5/7 properties, it requires that I send old data for 2/7 to re-write so that SetValues doesn't write nulls into my fields from my DTO.
Any help here would be awesome... totally new to this stuff and trying to learn everything right. Thank you.
I've taken similar approach to do optimization, and I've faced same issues with null values when attaching (not just null, you'll have issue with boolean as well). This is what I've come up with:
public static void Update<T>(this DbContext context, IDTO dto)
where T : class, IEntity
{
T TEntity = context.Set<T>().Local.FirstOrDefault(x => x.Id == dto.Id);
if (TEntity == null)
{
TEntity = context.Set<T>().Create();
TEntity.Id = dto.Id;
context.Set<T>().Attach(TEntity);
}
context.Entry(TEntity).CurrentValues.SetValues(dto);
var attribute = dto.GetAttribute<EnsureUpdatedAttribute>();
if (attribute != null)
{
foreach (var property in attribute.Properties)
context.Entry(TEntity).Property(property).IsModified = true;
}
}
That is extension method for DbContext. Here are the interfaces IDTO and IEntity:
public interface IDTO
{
int Id { get; set; }
}
public interface IEntity
{
int Id { get; set; }
Nullable<DateTime> Modified { get; set; }
Nullable<DateTime> Created { get; set; }
}
I'm using my custom EnsureUpdatedAttribute to annotate what properties should always be updated (to deal with nulls / default values not being tracked):
public class EnsureUpdatedAttribute : Attribute
{
public IEnumerable<string> Properties { get; private set; }
public EnsureUpdatedAttribute(params string[] properties)
{
Properties = properties.AsEnumerable();
}
}
And this is a sample of usage:
public class Sample : IEntity
{
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
public Nullable<DateTime> Modified { get; set; }
public Nullable<DateTime> Created { get; set; }
}
[EnsureUpdated("Active")] /// requirement for entity framework change tracking, read about stub entities
public class SampleDTO : IDTO
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[JsonIgnore] /// How to exclude property from going on the wire / ignored for serialization
public bool Active { get; set; }
}
[HttpPost]
public HttpResponseMessage SaveSample(SampleDTO dto)
{
dto.Active = true;
_ctx.AddModel<Sample>(dto);
_ctx.SaveChanges();
return NoContent();
}
return NoContent() is just extension for returning 204 (NoContent).
Hope this helps.
Theres a few options you have, you can create a stored procedure to update the required parts (I wouldnt do this), or you can manually select the fileds to update on the model before saving the context changes with EF.
Heres an example how to update a specific field:
public void UpdatePerson(int personId, string details)
{
var person = new Person() { Id = personId, Details = details };
db.Persons.Attach(personId);
db.Entry(person).Property(x => x.Details).IsModified = true;
db.SaveChanges();
}
It will depend on your scenario what you want to do, but generally speaking its fine to send your whole entity to be updated, and this is how i would approach your situation potentially changing in the future if needed.
I am using EF code first approach with fluent api. I am having one registration form in my application where in registering candidate can select multiple options from dropdown(Interested In Dropdown on Sign-Up form) that has a predefined set of options (which may increase in future but the chances are very rare). When the user submits the form I want to save this records to database. So I created following entities.
Participant Class where the registering candidates information will be saved
public class Participant
{
public Participant()
{
Interests = new Collection<Interest>();
}
[Key, ForeignKey("User")]
public int Id { get; set; }
[DisplayName("First Name")]
[StringLength(50, ErrorMessage = "First name cannot be more than 50 characters")]
[Required(ErrorMessage = "You must fill in first name")]
public string FirstName { get; set; }
[DisplayName("Last Name")]
[StringLength(50, ErrorMessage = "Last name cannot be more than 50 characters")]
[Required(ErrorMessage = "You must fill in last name")]
public string LastName { get; set; }
[Required(ErrorMessage = "You must indicate your full birthday")]
[DisplayName("Birthday")]
[DataType(DataType.DateTime)]
public DateTime BirthDate { get; set; }
[DisplayName("Gender")]
[Required(ErrorMessage = "You must select gender")]
public int Gender { get; set; }
public string Address { get; set; }
public int CountryId { get; set; }
public Country Country { get; set; }
[DisplayName("Zip code")]
[StringLength(10, ErrorMessage = "Zip code cannot be more than 10 characters")]
public string ZipCode { get; set; }
public string Mobile { get; set; }
public string PhotoUrl { get; set; }
public virtual User User { get; set; }
public virtual ICollection<Interest> Interests { get; set; }
public string MedicalConditions { get; set; }
}
Interest Class from where the Interested In dropdown on Sign-up form will get populate The user can select multiple options from the Interested In dropdown
Interest Class
public class Interest
{
public Interest()
{
Participants = new Collection<Participant>();
}
public int Id { get; set; }
public string InterestName { get; set; }
public virtual ICollection<Participant> Participants { get; private set; }
}
To hold each participants interest I created a ParticipantInterests table in DB with following schema. ParticipantInterests Id (PK) ParticipantId (FK from Participants table) InterestId (FK Interests table)
I added public virtual ICollection Participants { get; set; } in Interest model and
public virtual ICollection Interests { get; set; } in Participant model to form Many-To-Many association.
My Data Context class is as follows
public class STNDataContext : DbContext
{
public DbSet<Participant> Participants { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<Country> Countries { get; set; }
public DbSet<Interest> Interests { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<SecurityQuestion> SecurityQuestions { get; set; }
public DbSet<Tour> Tours { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Participant>()
.HasKey(p => p.Id);
modelBuilder.Entity<User>()
.HasOptional(u => u.Participant)
.WithRequired();
modelBuilder.Entity<Participant>()
.HasMany(p => p.Interests)
.WithMany(i => i.Participants)
.Map(m =>
{
m.ToTable("ParticipantInterests");
m.MapLeftKey("ParticipantId");
m.MapRightKey("InterestId");
});
modelBuilder.Entity<User>().HasRequired(u => u.Role);
modelBuilder.Entity<Participant>().HasRequired(p => p.Country);
modelBuilder.Entity<User>().HasOptional(u => u.SecurityQuestion);
}
public virtual void Commit()
{
base.SaveChanges();
}
Controller Action Code
public virtual ActionResult Register(StudentRegisterViewModel studentRegisterViewModel)
{
if (ModelState.IsValid)
{
if (_userService.IsUserExists(studentRegisterViewModel.Participant.User) == false)
{
studentRegisterViewModel.Participant.User.Username = studentRegisterViewModel.Username;
studentRegisterViewModel.Participant.User.Email = studentRegisterViewModel.Email;
studentRegisterViewModel.Participant.User.DateCreated = DateTime.Now;
studentRegisterViewModel.Participant.User.Id = 3;
studentRegisterViewModel.Participant.User.IsApproved = false;
studentRegisterViewModel.Participant.User.RoleId = 2;
studentRegisterViewModel.Participant.CountryId = 1;
var interests = new List<Interest>();
foreach (var interestItem in studentRegisterViewModel.SelectedInterests)
{
var interest = new Interest { Id = interestItem };
interest.Participants.Add(studentRegisterViewModel.Participant);
interests.Add(interest);
studentRegisterViewModel.Participant.Interests.Add(interest);
}
studentRegisterViewModel.Participant.Interests = interests;
_participantService.CreatParticipant(studentRegisterViewModel.Participant);
var user = _userService.GetUser(studentRegisterViewModel.Participant.User.Username);
}
}
studentRegisterViewModel.Gender =
Enum.GetNames(typeof(Gender)).Select(
x => new KeyValuePair<string, string>(x, x.ToString(CultureInfo.InvariantCulture)));
studentRegisterViewModel.Interests = _interestService.GetAllInterests();
return View(studentRegisterViewModel);
}
Participant Repository (DAL)
public class ParticipantRepository : Repository<Participant>, IParticipantRepository
{
public ParticipantRepository(IDatabaseFactory databaseFactory)
: base(databaseFactory)
{
}
}
Participant Service (BLL)
public class ParticipantService : IParticipantService
{
private readonly IParticipantRepository _participantRepository;
private readonly IUnitOfWork _unitOfWork;
public ParticipantService(IParticipantRepository participantRepository, IUnitOfWork unitOfWork)
{
this._participantRepository = participantRepository;
this._unitOfWork = unitOfWork;
}
public void CreatParticipant(Participant participant)
{
_participantRepository.Add(participant);
_unitOfWork.Commit();
}
}
Database Factory
public class DatabaseFactory : Disposable, IDatabaseFactory
{
private STNDataContext _stnDataContext;
public DatabaseFactory()
{
Database.SetInitializer<STNDataContext>(null);
}
public STNDataContext Get()
{
return _stnDataContext ?? (_stnDataContext = new STNDataContext());
}
protected override void DisposeCore()
{
if (_stnDataContext != null)
_stnDataContext.Dispose();
}
}
Unit of Work Class
public class UniOfWork : IUnitOfWork
{
private readonly IDatabaseFactory _databaseFactory;
private STNDataContext _stnDataContext;
public UniOfWork(IDatabaseFactory databaseFactory)
{
this._databaseFactory = databaseFactory;
}
public STNDataContext StnDataContext
{
get { return _stnDataContext ?? (_stnDataContext = _databaseFactory.Get()); }
}
public void Commit()
{
StnDataContext.Commit();
}
}
When I try to Create Participant I get following error.
Cannot insert the value NULL into column 'InterestName', table 'StudyTourNetworkDB.dbo.Interests'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated.
Ideally as per my thinking it should insert Participant Information in Participants table and Participants Interests in ParticipantsInterests table. But it is trying to insert record in Interests table also which should not happen. Please help me resolve this problem. I may be doing wrong by creating many-to-many association.
Thanks
Note : I could understand the problem as Interests collection does not get added / attach to context but I could not find out how to add Interest collection to the same context with repository pattern and unit of work.
Please provide me the solutions. Thanks in advance
You are correct in that your Interest objects are being re-added, because the copies held in your model are not being tracked by EF and therefore it thinks they are new. Instead, you will need to look up the versions from your repository, and add those instead.
Instead of:
var interests = new List<Interest>();
foreach (var interestItem in studentRegisterViewModel.SelectedInterests)
{
var interest = new Interest { Id = interestItem };
interest.Participants.Add(studentRegisterViewModel.Participant);
interests.Add(interest);
studentRegisterViewModel.Participant.Interests.Add(interest);
}
studentRegisterViewModel.Participant.Interests = interests;
Try something like:
// Look up the actual EF entities which match your selected items. You'll
// probably need to adapt this to make it work
var selectedInterestIds = studentRegisterViewModel.SelectedInterests.Select(i => i.Id);
var interests = _interestService.GetAllInterests().Where(i => selectedInterestIds.Contains(i.Id));
studentRegisterViewModel.Participant.Interests = interests;
Note that with a many-to-many relationship, you don't need to set both sides - in your example you were filling in the Participant field of the Interest entity - this will be set automatically by EF since you're adding it to the Interests property of the Participant.
I am trying to get to grips with EF4 CTP5. I have two classes that have a many-to-many relationship: Member and MemberGroup. CTP5 Code First generated two tables (Members and MemberGroups) and also a third named MemberGroupMembers that has two columns (MemberGroupId and MemberId) So far everything is as I was expecting it to be. I have seeded the database with some Members and MemberGroups. The problem is that I cannot find how to assign one or more MemberGroups to a Member, which would result in inserting a row into the MemberGroupMembers table for each MemberGroup that the Member is assigned to.
public class Member
{
public int Id { get; set; }
public Guid SecureId { get; set; }
public DateTime JoinedOn { get; set; }
public virtual ICollection<MemberGroup> MemberGroups { get; set; }
}
public class MemberGroup
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedOn { get; set; }
public virtual ICollection<Member> Members { get; set; }
}
public class CTP5testContext : DbContext
{
public CTP5testContext() : base("CTP5test") { }
public DbSet<Member> Members { get; set; }
public DbSet<MemberGroup> MemberGroups { get; set; }
}
public class CTP5testContextInitializer : DropCreateDatabaseIfModelChanges<CTP5testContext>
{
protected override void Seed(CTP5testContext context)
{
new List<Member>
{
new Member
{
Id = 1,
SecureId = Guid.NewGuid(),
JoinedOn = DateTime.Now
}
,
new Member
{
Id = 2,
SecureId = Guid.NewGuid(),
JoinedOn = DateTime.Now
}
}.ForEach(m => context.Members.Add(m));
var memberGroup = new MemberGroup()
{
Id = 1,
Name = "MemberGroup 1",
CreatedOn = DateTime.Now
};
context.MemberGroups.Add(memberGroup);
// How can I assign Member 1 to MemberGroup 1 ?????
context.SaveChanges();
}
}
I hope that it is clear what I am trying to do here and that someone can give me an example of how to achieve this.
Regards,
Erwin
You must use collections defined in your POCO classes. So if you want to assign member1 to memberGroup you will simply call:
memberGroup.Members.Add(member1);