Common configuration in entity framework 5 - entity-framework

I have a couple of entities, all inherits base entity with auditing and ID fields. In the configuration for each property I have absolutely same lines like:
this.HasKey(t0 => t0.Id)
.Map(m => m.ToTable("templates"))
.Property(x => x.Id)
.HasColumnName("id")
...................
Is there way to move this code to some kind of "base configuration" to not to write it for each entity?

All you'd need to do is to implement either Table-Per-Type or Table-Per-Hierarchy:
In Table-Per-Type your entities will be split into different tables, but all offshoot tables will have its PK be a FK to the base entity table.
In Table-Per-Hierarchy your entities will all be in one table, but EF will generate a discriminator to discern which object type the entity is actually a part of.
For a clearer example of this, check out the post at this site.

Related

Mapping TPT inheritance in Entity Framework 6 (core)

Consider two tables, table BaseService with PK ID, and table SubService with PK BaseServiceID, which is a foreign key to ID in the BaseService table. I wish to map these to classes in EF6 where SubService inherits from BaseService. I'm not sure how to describe in the mapping that the foreign key is from SubService.BaseServiceID to BaseService.ID. At the moment I have something like this:
modelBuilder.Entity<SubService>(e => {
e.ToTable("SubService");
});
and
modelBuilder.Entity<BaseService>(e => {
e.ToTable("BaseService");
e.HasKey(x => x.ID);
});
When I query though, the resulting query tries to join using BaseService.ID to SubService.ID. I've tried a few variations on my mapping, but I'm getting nowhere - can anyone suggest how this should be done?
From my testing, EF doesn't currently support having different column names for the keys in the tables in a TPT mapping. If you configure one entity to map its "Id" property to a column called "FooId", then all entities in the hierarchy will map their keys to "FooId".
You can create an EF Core Issue to provide feedback on this scenario.
modelBuilder.Entity<SubService>()
.ToTable("SubService")
.HasRequired(s => s.BaseService)
.WithMany(b => b.SubServices)
.HasForeignKey(s => s.BaseServiceID);
In this example, a HasRequired method is used to specify that the entity requires a and the method is used to specify the ability to navigate on the side of the relationship. Finally, `BaseService' property class'SubService' 'BaseService' 'WithMany' 'BaseService' 'HasForeign' 'KeyBase' 'ServiceID' 'SubService'

How do I set up EF Core to cascade delete on a one to one relationship?

I'm trying to get cascade delete working for a one to one relationship in EF Core 5. When I delete a ParentTable entity, I want the associated ChildTable entity to be deleted from the database as well.
The database is set up in this way:
ParentTable
Id
ChildId (FK, unique)
ChildTable
Id
And configure it in EF Core for the Parent entity this way:
builder.HasOne(o => o.ChildTable)
.WithOne()
.HasForeignKey<ParentTable>("ChildId")
.OnDelete(DeleteBehavior.Cascade);
When I remove a ParentTable entity from the context, it does not also remove the ChildTable. I must be missing something, but I don't know what that is.
Any help is appreciated. Thank you.
When writing HasForeignKey<ParentTable>("ChildId") you specify the to be the dependent entity. Therefore the relationship between the entities have been reversed from what you want it to be. Try switching it to something similar to:
builder.HasOne(x => x.ChildTable).WithOne().HasForeignKey<ChildTable>(x => x.ForeignKey).OnDelete(DeleteBehavior.Casacade)
Check this link out if you want the Microsoft's documentation on the topic: https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key#one-to-one

How can I use SQL many-to-many table from Entity Framework?

I am developing for an existing application which uses a SQL database that is used by two applications. One uses Entity Framework to connect to the database. The other uses LINQ-to-SQL. The SQL database is designed so that there are some tables showing many-to-many relationships between rows in two tables. Entity Framework seems not to import these tables, apparently because it has some object-oriented idea for how many-to-many relationships ought to be represented. So far, the Entity Framework application has not needed to know about those tables, but now it should. I don't know how that works, and I am concerned that even if I learn about Entity Framework's exciting new way to represent these relationships, that it won't cooperate nicely with the other application or the database which is designed to use the many-to-many table.
I.e., there is a table of Foos, and a table of Bars, and then a table with Foo and Bar Ids that lists which Foos relate to which Bars, and I don't want to stop using this relationship table, particularly because there is another LINQ application that heavily uses this relationship table.
Questions:
If I learn to use Entity Framework's many-to-many system, will it use and update the many-to-many table that the other application uses?
If not, what is a good way to get Entity Framework to not ignore the many-to-many relationship table, so I can write code to use the existing table?
Yes, Entity Framework will manage your many-to-many tables for you. Pure link tables (that only have two foreign key columns) in EF are represented as relationships as opposed to POCO objects. The way this is done is that you tell EF that there is a relationship between two of your objects and that table X is where this relationship is stored. As an example in EF 4.1. which is what I'm currently using this is done like so:
modelBuilder.Entity<Foo>() //Let me tell you about Foo...
.HasMany(f => f.Bars) //The property in the Foo class that links to Bar objects is Bars
.WithMany(b => b.Foos) //The property in the Bar class that links to Foo objects is Foos
.Map(m => {
m.MapLeftKey("FooID"); //Name of the foreign key column in the link table for Foo
m.MapRightKey("BarID"); //Name of the foreign key column in the link table for Bar
m.ToTable("FooBar"); //Name of the link table
});
You can then make changes to this table by linking/unlinking objects in your code. You pretty much do something like
myFoo.Bars.Add(myBar); //Add a row to the link table
myFoo.Bars.Remove(myBar) //Delete a row from the link table
For a full implementation you should google your version of EF.
In case of link tables that contain extra columns (for example a creation date) they are represented by a POCO just like all the other tables. If you're really paranoid about EF's ability to manage your link tables you can force it to go this route by adding a unique id column to your pure link tables, but I'd definitely advice against it.
Think of it this way: EF has been around for a while now and has achieved a certain degree of maturity. Combine this with the fact that many-to-many relationships are not exactly rare in databases. Do you really think the designers of EF haven't dealt with your case?

EntityFramework Join table with more than 2 entities

I have 4 tables/entities which fall into two groups, alerts and recipients. Either entity from a group can map to either entity of the other group (an Alert can have many Recipients and RecipientGroups and so on).
Tables:
Alerts
AlertGroups (1 to many relationship with alerts)
Recipients
RecipientGroups (many to many relationship with recipients)
Instead of making 4 jointables (AlertRecipients, AlertRecipientGroups, etc.) I want to make one join table with 4 columns, each column being a nullable FK for one of my entity types.
I've made the table in SQL, and set up my context using Fluent API like so:
modelBuilder.Entity<AlertGroup>()
.HasMany(ag => ag.RecipientGroups)
.WithMany(rg => rg.AlertGroups)
.Map(m => m.ToTable("AlertRecipients")
.MapLeftKey("AlertGroupID")
.MapRightKey("RecipientGroupID"));
modelBuilder.Entity<AlertGroup>()
.HasMany(ag => ag.Recipients)
.WithMany(rg => rg.AlertGroups)
.Map(m => m.ToTable("AlertRecipients")
.MapLeftKey("AlertGroupID")
.MapRightKey("RecipientID"));
But I get this error:
Schema specified is not valid. Errors:
(251,6) : error 0019: The EntitySet 'AlertGroupRecipient' with schema
'dbo' and table 'AlertRecipients' was already defined. Each EntitySet
must refer to a unique schema and table.
Is there a workaround to do what I'm trying to do?
EF is not able to do that this way. With EF you need separate join table for every many-to-many relationship (because that is the way how you should do that). If you want to do that your way you cannot use many-to-many association in the mapping. You must instead "upgrade" your AlertRecipients to the real entity (another class in your model) and handle everything like one-to-many association.

EF CF: many-to-many relation with additional info

We have legacy database and we map the new objects and props to the old tables and columns. So far so good. We have many-to-many relation which was mapped successfully. The intermediate table contains additional data. When we try to map the intermediate table to an object we get exception that the mapping is already defined. If we remove mapping from any side of the relation we get error that table is missing (ofc, we expect just that). I can do that easily with NHibernate and I am starting to think that EF is missing really really many features. So, please, tell me I am wrong and we can do that with EF.
Best regards
EDIT: here is a dummy sample which fails.
class User
{
public ICollection<User> Followers{get;set;}
}
class UserRelation
{
public User User{get;set;}
public User Follower{get;set;}
public DateTime CreatedOn{get;set;}
}
user mapping
modelBuilder
.Entity<User>()
.HasMany<User>(user => user.Followers)
.WithMany()
.Map(m =>m.MapLeftKey("user_id").MapRightKey("follower_id")
.ToTable("user_follower"));
user relation mapping
modelBuilder
.Entity<UserRelation>()
.ToTable("user_follower");
modelBuilder
.Entity<UserRelation>()
.HasOptional<User>(f => f.User)
.WithRequired().Map(m => m.MapKey("user_id"));
modelBuilder
.Entity<UserRelation>()
.HasOptional<User>(f => f.Follower)
.WithRequired().Map(m => m.MapKey("follower_id"));
modelBuilder
.Entity<UserRelation>()
.Property(entity => entity.CreatedOn)
.HasColumnName("created_on");
Exception
Schema specified is not valid. Errors:
(67,6) : error 0019: The EntitySet 'UserUser' with schema 'dbo' and table 'user_follower' was already defined. Each EntitySet must refer to a unique schema and table.
Edit2: Here is another example of this model: http://learnentityframework.com/LearnEntityFramework/tutorials/many-to-many-relationships-in-the-entity-data-model/
Direct many-to-many mapping is available only if junction table contains just foreign keys. If you want to expose other properties in junction table you must map it to separate entity and mapt two one-to-many relations from former entities used in many-to-many.
I'm actually not able to write you the code because I don't understand your example.
Try only (don't map Many-to-many in User):
modelBuilder.Entity<UserRelation>
.HasRequired(r => r.User)
.WithMany(u => u.Followers);
modelBuilder.Entity<UserRelation>
.HasRequired(r => r.Follower)
.WithMany();
EF maps many-to-many relationships as properties of the related objects.
So, let's say you have Cars and Drivers that are related m-to-n. In your EF model, you will see that each Car object has a Drivers collection as a property, and each Driver object has a Cars collection as a property.
That is how m-to-n relationships are modeled in EF.