How do I override the default convention for the foreign key column in EF4 to specify a different column name?
For example, I have one entity with a property called Parent that references to other one of the same type.
EF4 tries to resolve the relation by looking for the foreign key named EntityId, but in my DB schema it is Entity_Id. How do I tell EF that the FK column name is not EntityId?
I've tried the following:
modelBuilder.Entity<SomeEntity>()
.HasOptional(m => m.Parent)
.WithMany()
.IsIndependent()
.Map(m => m.MapKey(k => k.Id, "Entity_Id")));
But I get an exception saying: Sequence contains more than one matching element.
Any help on this?
Thanks!
First: Upgrade to EF 4.1 RTW. CTP 5 is outdated and contains potentially many bugs which are fixed now.
If you have done the upgrade the following should work:
modelBuilder.Entity<SomeEntity>()
.HasOptional(m => m.Parent)
.WithMany()
.Map(c => c.MapKey("Entity_Id"));
Related
I have a Person class which can have Relatives which is a self reference many-to-many relationship(Relative is also a Person). I wanted to maintain this Person->Relatives mapping in a separate table. So, to create this relationship in EF, I did this:
modelBuilder.Entity<Person>()
.HasMany(e => e.Relatives)
.WithMany()
.Map(c =>
{
c.MapLeftKey("PersonId");
c.MapRightKey("RelativeId");
c.ToTable("PersonRelative");
});
Now, this created a new table PersonRelative with two columns PersonId and RelativeId automatically as I planned. It also have composite primary key on PersonId and RelativeId.
Now, there're two things I wish to do here:
I want to add a new identity "Id" column in this new PersonRelative table for better performance. How can I do that?
Now, can I create a separate class for PersonRelative table, the way we have a class for every table. Because that would try creating the table again. So, I think I can either keep that fluent api mapping or the PersonRelative class. Is this correct?
I would really appreciate any help here.
you can achieve two points by the following code:
modelBuilder.Entity<PersonRelative>().HasKey(x => x.Id);
modelBuilder.Entity<PersonRelative>()
.HasOne<Person>(x => x.Person)
.WithMany(s => s.PersonRelative)
.HasForeignKey(x => x.PersonId);
modelBuilder.Entity<PersonRelative>()
.HasOne<Realtive>(x => x.Realtive)
.WithMany(s => s.PersonRelative)
.HasForeignKey(x => x.RelativeId);
it's how to make many-to-many relation in entity framework core, as it's not supported yet in core, you can use it in non-core entity framework too.
Please Note, if you want a new table mapping just for accessing data with navigation properties, then you can add property of type "ICollection" for Students in Relative Class, and the same for Student Class you can add ICollection for access Relatives from Student
My question is a bit similar to this, although I use EF6.
The problem is that I have two entities which are connected through a mapping table - and have a many-to-many relationship like this for example:
modelBuilder.Entity<Team>()
.HasMany(t => t.Members)
.WithMany()
.Map(c =>
{
c.ToTable("TeamMemberMapping");
});
So in this example one team can have multiple members and one guy can be a part of multiple teams.
The problem with this is when I delete a guy, all his team mappings will be deleted, because Entity Framework uses cascade delete by default as a delete action.
I'd like to turn this off - so the DB shouldn't allow to delete a guy, if he is a part of some team.
I know that I can remove the many-to-many cascade delete convention globally with this:
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
But this is too harsh for me. I would like to do this only for this table.
My other idea is (since I use code-first migrations) removing the convention just temporarily, so I can generate an update step which would drop all the foreign keys:
DropForeignKey("dbo.TeamMemberMapping", "Employee_Id", "dbo.Employee");
DropForeignKey("dbo.TeamMemberMapping", "Team_Id", "dbo.Team");
DropForeignKey("dbo.SomeOtherMapping", "Some_Id", "dbo.SomeTable");
DropForeignKey("dbo.SomeOtherMapping", "Other_Id", "dbo.OtherTable");
AddForeignKey("dbo.TeamMemberMapping", "Employee_Id", "dbo.Employee", "Id");
AddForeignKey("dbo.TeamMemberMapping", "Team_Id", "dbo.Team", "Id");
AddForeignKey("dbo.SomeOtherMapping", "Some_Id", "dbo.SomeTable", "Id");
AddForeignKey("dbo.SomeOtherMapping", "Other_Id", "dbo.OtherTable", "Id");
Now I can edit this migration to skip all the other mappings (like "SomeOtherMapping") and only deal with "TeamMemberMapping".
Then I would revert my temporary change (e.g. removing the convention)
Is there any drawbacks of this solution? Because it seems to be a workaround for me.
Is there any other solution?
I've created two entities which are related to each other by joining using three columns, both are views on the database. For the Travel I have the Id, FromCityId and ToCityId, for TravelCost I have the TravelId, FromCityId and ToCityId. The fluent mapping is as below
TravelEntityConfiguration class:
HasMany(x => x.Amounts)
.WithRequired()
.HasForeignKey(x => new
{
x.TravelId,
x.FromCityId,
x.ToCityId
});
and for the travel cost its
TravelCostEntityConfiguration
HasRequired(x => x.Travel)
.WithMany()
.HasForeignKey(x => new
{
x.TravelId,
x.FromCityId,
x.ToCityId
});
When i query these entities and include the navigation property
context.Set<Table>().Include(x => x.TravelCost)....
For each result only the first of the child collection is loaded. I checked the query generated, even the query is correct it returns the full set with all the children and the join is correctly. What am i missing here. Need some help no clue for the moment. basically i suspect the mapping is not correct but didn't found out the problem yet.
Thank you Asad, you lighted up my problem. The problem was with the Id of the TravelCost view which were generated on the fly and ended up to be the same so EF thinks it is the same record, the mapping was totally correct.
I would like Entity Framework v6 to not use quotes around identifiers when executing transactions against the database. Is it possible to configure the DbContext to do this without creating a configuration file for every entity?
For example:
Instead of
SELECT "ApplicationId"
FROM "dbo"."Applications";
I want
SELECT ApplicationId
FROM dbo.Applications;
Will Entity Framework be able to correctly map properties and entities to the database fields and tables correctly?
EDIT:
Rather than try to eliminate the quotation marks, I should have indicated that my goal is to interface with an Oracle DB. Oracle will require using quotation marks around identifiers that contain lowercase letters. So, I should probably change my request to indicate that I need all uppercase identifiers.
I came up with part of a solution in the OnModelCreating method of the DbContext, but it won't handle Foreign Key identifiers:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Properties()
.Configure(c => c.HasColumnName(c.ClrPropertyInfo.Name.ToUpperInvariant()));
modelBuilder.Types()
.Configure(c => c.ToTable(c.ClrType.Name.ToUpperInvariant()));
}
You can put the foreign key properties in your class, and then map their database column. Like this How to configure DbContext to work with Oracle ODP.Net and EF CodeFirst?
Or, if you don't want to put the foreign key property in the classes, you should use the fluent API to map the foreign key using uppercase letters. Like this example:
modelBuilder.Entity<Course>()
.HasRequired(c => c.Department)
.WithMany(t => t.Courses)
.Map(m => m.MapKey("CHANGEDDEPARTMENTID"));
I have an optional relationship from a Child to a Parent class. I would like to get an exception on SubmitChanges when the parent object is marked for deletion if there are still children around that reference it.
The configuration I've tried is this (there is no navigation property from the parent to the children):
modelBuilder.Entity<Child>()
.HasOptional<Parent>(child => child.Parent)
.WithMany()
.HasForeignKey(child => child.ParentId)
.WillCascadeOnDelete(false);
Like this EF sets the children's ParentId property to null when deleting the parent, which is not what I want.
It works if the relationship is configured as required:
modelBuilder.Entity<Child>()
.HasRequired<Parent>(child => child.Parent)
.WithMany()
.HasForeignKey(child => child.ParentId)
.WillCascadeOnDelete(false);
This throws an exception, which would be the desired behaviour. But the relationship has to be optional. Is this possible with EF 4.3.1 using Code First?
No. That is the difference between optional and required. Required = must have a principal record and if you delete the principal record without cascading you will get an exception. Optional = doesn't need a principal record and if you delete the principal record without cascading the FK is set to null.
If you need anything else you must handle it yourselves.