I'm using the CTP 5 of EF 4 and Code first.
I don't get a many-many relation working with a composite key on one side.
modelBuilder.Entity<Item>()
.HasMany(i => i.Categories)
.WithMany(o => o.Items)
.Map(
mc =>
{
mc.ToTable("ItemCategories");
mc.MapLeftKey(i => i.Id, "ItemId");
mc.MapRightKey(o => o.TemplateID, "TemplateId");
mc.MapRightKey(o => o.ItemId, "ItemId");
}
);
So instead of having a simple key for Categories in my matching table, I've got a composite one. And one part of the composite key is also the key for the Item type,
which seems to be the problem here.
I get the error: "Each property name in a type must be unique. Property name 'ItemId' was already defined."
How can I configure EF to use a composite key in this case?
Of course you cannot have 2 columns with the same name within one table. This will work:
modelBuilder.Entity<Item>()
.HasMany(i => i.Categories)
.WithMany(c => c.Items)
.Map(m =>
{
m.MapRightKey(i => i.Id, "ItemId");
m.MapLeftKey(c => c.ItemId, "ItemId2");
m.MapLeftKey(c => c.TemplateId, "TemplateId");
});
public class Category
{
[Key]
public string ItemId { get; set; }
[Key]
public string TemplateId { get; set; }
public string Value { get; set; }
public ICollection<Item> Items { get; set; }
}
public class Item
{
public string Id { get; set; }
public string Name { get; set; }
public ICollection<Category> Categories { get; set; }
}
The mapping table ItemCategories is not a POCO, but used for mapping those 2 as
shown.
It has SQL columns
Id (own primary key)
ItemId (FK to Item table and Category table)
TemplateId (FK to Category table)
and another ID column which maps to a different table.
In my opinion the only difference here to "normal" many-many scenario is the composite key
in the ItemCategories table, which builds the relation to the Category table.
Related
This is what i am trying to achieve :
modelBuilder.Entity<ApplicationUser>()
.HasMany(u => u.Following)
.WithMany(u => u.Followers)
.Map(m =>
{
m.ToTable("FollowTables");
m.MapLeftKey("UserId");
m.MapRightKey("FollowId");
});
In application user class, i have configured following and followers like this:
public ICollection<ApplicationUser> Following { get; set; }
public ICollection<ApplicationUser> Followers { get; set; }
follow table should be something like this:
public class FollowTable
{
[Key]
public int autoId { get; set; }
public int UserId { get; set; }
public int? FollowId { get; set; }
}
autoId is primary key and UserId and FollowId both are foreign key to ApplicationUser class where UserId is user's own id and FollowId are the ids which user is following.Its data could be following:
autoId UserId FollowId
1 4 11
2 4 12
3 4 13
Now, i problem is when i update database through pmc, it is creating two database tables one is FollowTables with column (USerId, FollowId) and one is FollowTables1(autoId, USerId, FollowId).
If i remove this line from applicationDbContext class:
public DbSet<FollowTable> FollowTables { get; set; }
then its creating only one table but with no primary key.
please someone help me out . how to properly configure UserId and followId as foreign key and these two should map to ApplicationUser's Id.
I want to use those Collection's following and Followers too.how to do it.
You have to decide if you want to work with an entity that represents the junction table or not. If you don't need to add any other properties to that table, excluding the FKs, then I suggest you don't map the junction table as entity. It is going to be more easy for you due to Entity Framework will handle that table for you.
Now if you really need to map that table then you need to delete many-to-many fluent api configuration and change the type of your navigation properties:
public ICollection<FollowTable> Following { get; set; }
public ICollection<FollowTable> Followers { get; set; }
That is going to create two one-to-many relationships with the junction table, an explicit representation of a many-to-many relationship. To do that you also need to do some changes in that entity:
public class FollowTable
{
[Key]
public int autoId { get; set; }
public int UserId { get; set; }
[ForeignKey("User")]
public ApplicationUser User{ get; set; }
[ForeignKey("Follow")]
public int? FollowId { get; set; }
public ApplicationUser Follow{ get; set; }
}
Also, I don't think FollowId Fk property should be a nullable FK, because you want to represent a relationship between two persons.
If you ask my opinion about what option you should take, I suggest you don't map the junction table if you are going to have only those properties.
asp.net mvc 4, Entity Framework 5, SQL Server 2012 Express, Code First
I have a Place model:
public virtual int PlaceID { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
public virtual string Name { get; set; }
and a related Tag model:
public virtual int TagID { get; set; }
public virtual string Name { get; set; }
public virtual string NamePlural { get; set; }
public virtual ICollection<Place> Places { get; set; }
they have a many to many relationship.
I have a List places - and I would like to create a List tags - populated with every (unique) tag associated with every place in 'places'.
For example, one place might have 'restaurant' and 'pub' tag, another 'pub' and 'bar', and another 'shop' and 'cafe'.
I would like the List to contain one of each of the tags with these names:
Bar, Cafe, Restaurant, Pub, Shop
How can I do this in Linq?
Thanks.
If you want all the unique tag names you can do:
places.SelectMany(x => x.Tags).Select(x => x.Name).Distinct()
if the two instances of the same tag are the same object then you can just do
places.SelectMany(x => x.Tags).Distinct();
if they are different objects then you can do
places.SelectMany(x => x.Tags).GroupBy(x => x.TagId).Select(g => g.First());
UPDATE after new comment.
Add ToList() to then end to convert the result into a list.
places.SelectMany(x => x.Tags).Select(x => x.Name).Distinct().ToList();
places.SelectMany(x => x.Tags).Distinct().ToList();
places.SelectMany(x => x.Tags).GroupBy(x => x.TagId).Select(g => g.First()).ToList();
So I have the following models
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Appointment
{
public int Id { get; set; }
public string Name{ get; set; }
}
and I want them assigned to a another table with a separate primary key like so
public class UserAppointment
{
public int Id { get; set; }
public int UserId { get; set; }
public int AppointmentId { get; set; }
public virtual Appointment Appointment {get;set;}
public virtual User User {get;set;}
}
What I wanted is the Id be a key (unique, auto generate, etc) while at the same time will force the UserId and AppointmentId to have a unique combination as well.
eg
this is what i want
Id UserId AppointmentId
1 1 2
2 1 3
and not this
Id UserId AppointmentId
1 1 2
2 1 2
3 1 2
At the moment I did some modelbuilder statements on my context to configure my keys
modelbuilder.Entity<UserApointment>()
.HasRequired(e => e.User)
.HasMany(u => u.Appointment)
.HasForeignKey(e => e.UserId);
modelbuilder.Entity<UserApointment>()
.HasRequired(e => e.Appointment)
.HasMany(u => u.Users)
.HasForeignKey(e => e.AppointmentId);
But it will still let me insert records with similar user and appointment ids.
Any advice on how to deal with this is very much appreciated!
Thanks!!
You can tackle this at the database level by simply creating a unique constraint on the UserAppointment table.
ALTER TABLE UserAppointments
ADD CONSTRAINT uc_UserAppointment UNIQUE (UserID,AppointmentID)
On Entity Framework (which I am not familiar with) seems to be done like this:
modelbuilder.Entity<UserApointment>().HasKey(x=> new { x.UserId,x.AppointmentId});
Read more here., specially the remark:
If the primary key is made up of multiple properties then specify an
anonymous type including the properties. For example, in C# t => new {
t.Id1, t.Id2 }
UPDATE
Probably a Unique Index serves your purposes better:
CREATE UNIQUE INDEX IX_UserAppointment
ON UserAppointment (UserId, AppointmentId)
This unique index will ensure that no duplicate combination of UserId and AppointmentId will ever exist in the table and will also speed up your queries.
I need to map a many-to-many relationship using Entity Framework Code First. Its a standard socialnetworking FriendRequests mapping. A User Object has a Collection of FriendRequests of type List<User>. In the database I'm using a join table for the relationship as follows:
CREATE TABLE dbo.FriendRequests(
UserId INT NOT NULL FOREIGN KEY REFERENCES dbo.Users(id),
FriendId INT NOT NULL FOREIGN KEY REFERENCES dbo.Users(id),
RequestDate SMALLDATETIME NOT NULL DEFAULT GETUTCDATE())
GO
ALTER TABLE dbo.FriendRequests ADD PRIMARY KEY (UserId,FriendId)
GO
How do I map the user object in Entity Framework Code First to enable a Collection via a join table?
You can try it this way:
public class User
{
public int Id { get; set; }
public ICollection<FriendRequest> FriendRequests { get; set; }
}
public class FriendRequest
{
public int UserId { get; set; }
public int FriendId { get; set; }
public DateTime RequestDate { get; set; }
public User User { get; set; }
public User Friend { get; set; }
}
Mapping with Fluent API:
modelBuilder.Entity<User>()
.HasMany(u => u.FriendRequests)
.WithRequired(f => f.User)
.HasForeignKey(f => f.UserId);
modelBuilder.Entity<FriendRequest>()
.HasKey(f => new { f.UserId, f.FriendId });
modelBuilder.Entity<FriendRequest>()
.HasRequired(f => f.Friend)
.WithMany()
.HasForeignKey(f => f.FriendId);
Because of the RequestDate property in the link table you cannot map this as a many-to-many relationship. Instead you need two one-to-many relationships as shown above.
Possibly you need to disable cascading delete, I am not sure. You can do this by appending .WillCascadeOnDelete(false) at the end of the two one-to-many mappings.
Edit
To your comment: If you remove the RequestDate column you can create your model with a many-to-many relationship. You don't need the FriendRequest entity in this case:
public class User
{
public int Id { get; set; }
public ICollection<User> FriendRequests { get; set; }
}
Mapping with Fluent API:
modelBuilder.Entity<User>()
.HasMany(u => u.FriendRequests)
.WithMany()
.Map(m =>
{
m.ToTable("FriendRequests");
m.MapLeftKey("UserId");
m.MapRightKey("FriendId");
});
I have 2 tables:
1) Parent
2) Child
In codefirst I have the following definition:
public class Parent
{
public int ParentId { get; set; }
public ICollection<Child> child { get; set; }
}
However in the db, the child table has the following foreign key defined:
ParentParentId (FK, int, NULL)
How do I ensure it just specifies ParentId in the foreign key? Do I need to explicitly set the parent key using the fluent configuration?
Yes you must either include Foreign key property in the child entity:
public class Child
{
public int ChildId { get; set; }
public int ParentId { get; set; } // FK
public virtual Parent { get; set; }
}
Or you must rename the column with fluent API:
modelBuilder.Entity<Child>()
.HasRequired(c => c.Parent)
.WithMany(p => p.Childs)
.Map(m => m.MapKey("ParentId"));