Populating a linking table in a many-to-many relationship - entity-framework-4

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);

Related

What is the right way to create related entities with many-to-many relationships

I am new to Entity Framework. Just wondering what is the right way to create related entities with many-to-many relationships. I always get this error when debugging: "Object reference not set to an instance of an object".
Take the following as an example:
Below is the data model, a Club can have multiple Members, a Member can join multiple clubs
public class Club
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Member> Member { get; set; }
}
public class Member
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Club> Club { get; set; }
}
I tried to create a new Club and add a new Member to it (Neither object is existing data in the DB):
Member member = new Member();
Club club=new Club();
member.Name = "Amy";
club.Name="NBA Fans";
member.Club.Add(club); //Error: Object reference not set to an instance of an object
db.Member.Add(member);
db.SaveChanges();
Can anyone please provide the right way to do this?
Thanks a lot
You can try this
Edit :
Follow this link Saving Many to Many relationship data on MVC Create view
public class Club
{
public int ClubId { get; set; }
public string Name { get; set; }
}
public class Member
{
public int MemberId { get; set; }
public string Name { get; set; }
}
Edit Class :
public class ClubMembers
{
public int ClubMember { get; set; }
public List<Member> Member { get; set; }
public List<Club> Club { get; set; }
}
List<Club> clubList=new List<Club>();
Club club = new Club();
club.ClubId=1;
club.Name="Club1";
clubList.Add(club);
List<Member> memberList = new List<Member>();
Member member = new Member();
member.MemberId = 1;
member.Name = "Govinda";
memberList.Add(member);
ClubMembers clubMembers=new ClubMembers();
clubMembers.Club = clubList;
clubMembers.Member=memberList;
foreach (var item in clubMembers.Club)
{
//do code for club entity
}
foreach (var item in clubMembers.Member)
{
//do code for member entity
}

how to query against a many to many relation with entity framework 6

I have those 2 Models
public class BranchEmployees
{
public int ID { get; set; }
[Required, Column(Order = 0), Key]
public string ApplicationUserID { get; set; }
[Required, Column(Order = 1), Key]
public int BranchID { get; set; }
public virtual ICollection<ApplicationUser> ApplicationUser { get; set; }
public virtual ICollection<Branch> Branch { get; set; }
}
public class Branch
{
public int ID { get; set; }
public string BranchName { get; set; }
[Required]
public string ApplicationUserID { get; set; }
public ApplicationUser User { get; set; }
public virtual ICollection<BranchEmployees> BranchEmployees { get; set; }
}
public class ApplicationUser
{
//rest of the code
}
UPDATE
I have everything set up but what I want is the query that gets me the Employees whose IDs are in the branch employees table
, I'm using entity framework code first with MVC 5 , how do I do it ?
Assuming that your ApplicationUser class will have a navigational property called BranchEmployees, here is the query that gets me the Employees whose IDs are in the branch employees table
List<ApplicationUsers> employeeNames =
dbContext
.ApplicationUsers
.Where(au => au.BranchEmployees
.Count() > 0).ToList();
Also, can you provide whole model including ApplicationUser? I also wonder why you do not prefer BranchEmployees to inherit from ApplicationUser.
You don't need a class that indicates a many-to-many relation between two tables when you do code-first. The key here is to create virtual properties of those classes. Lets say you have a class Student and class Course. Students can be in many Courses and Courses can have many Students. To generate a database using these models the classes should look like this:
public class Student
{
private ICollection<Course> _courses;
public Student()
{
this._courses = new HashSet<Course>();
}
[Key]
public int Id { get; set; }
public string FullName { get; set; }
public virtual ICollection<Course> Courses
{
get { return this._courses; }
set { this._courses = value; }
}
}
And for Course:
public class Course
{
private ICollection<Student> _students;
public Course()
{
this._students = new HashSet<Student>();
}
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students
{
get { return this._students; }
set { this._students = value; }
}
}
I hope that this can help you solve your issue.

Entity framework Entities in 'xxContext.x' participate in the 'x_y' relationship error

Before me, one developer used Entity Framework code first. I am not good at EF code first, so when I try to insert data, my code gives this error:
Entities in 'TourismContext.HotelOrders' participate in the 'HotelOrder_Order' relationship. 0 related 'HotelOrder_Order_Target' were found. 1 'HotelOrder_Order_Target' is expected.
This is my insert code:
var hotelOrdersInsert = new Data.Entities.HotelOrder
{
OrderId = odr.ID // this gives 7
HotelID = 13,
StartAt = DateTime.Now, // arrivalDate,
EndAt = DateTime.Now, // departureDate,
PaymentTypeID = 1,
PaymentStatusID = 1,
PaymentIdentifier = "a",
TotalRate = Convert.ToDecimal(total),
CurrencyID = 1
};
db.HotelOrders.Add(hotelOrdersInsert);
db.SaveChanges();
And this is my HotelOrder class:
public class HotelOrder
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Required]
public int HotelID { get; set; }
public int OrderId { get; set; }
// other properties
public virtual Order Order { get; set; }
public virtual Hotel Hotel { get; set; }
}
This is my Order class:
public class Order
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public virtual HotelOrder HotelOrder { get; set; }
}
Where can I find the relationship between the order and hotel order models?
You must write this relation as follows:
public class HotelOrder
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Required]
public int HotelID { get; set; }
[ForeignKey("Order")]
public int OrderId { get; set; }
public Order Order { get; set; }
[ForeignKey("Hotel")]
public int HotelId { get; set; }
public Hotel Hotel { get; set; }
}
public class Order
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public List<HotelOrder> HotelOrders { get; set; }
}
The problem is the relationship between HotelOrder and Order. It's most likely that you have a 1 to 1 relation. Meaning, Every HotelOrder must have an Order.
The relation is probably defined in the so called fluent API. Check the OnModelCreating(DbModelBuilder) function override of your class derived from DbContext. It probably states something like this:
modelBuilder.Entity<HotelOrder>().HasRequired(hotel_order => hotel_order.Order).WithRequiredPrincipal();
This tells EntityFramework that every HotelOrder must have an Order.
Alternatively, the relationship could be defined as DataAnnotations. Like Elvin Mammadov explained in his answer.
At this point the solution becomes obvious. You need to add an instance of Order to your HotelOrder instance before adding it to db.HotelOrders.

asp.net mvc 4 many-to-many relation how do I insert data

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();
}
}

Adding dynamic attributes to a model

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..

Resources