How can do I use fluent nhibernate to map this relationship? - c#

I have the following database tables:
Project table
Dependency table with columns (Id, ProjectId, DependentProjectId)
on my Project domain object i have the following mapping to be able to take a project and read its dependencies
public virtual IList<Dependency> Dependencies { get; set; }
HasMany(x => x.Dependencies).AsBag().Inverse().Cascade.AllDeleteOrphan().Fetch.Select().BatchSize(80);
I now want to create another property on the Project object to read all of the items where it is the dependent project (to find out the list of projects that has "me" as a dependency.
what is the correct way to do that mapping in fluent nhibernate?

I'd say you would just have to specify the .KeyColumn for the one to many relation, e.g.
HasMany(x => x.Dependencies)....KeyColumn("ProjectId")
HasMany(x => x.DependentProjects)....KeyColumn("DependentProjectId")

Related

Ways to map database with Entity Framework?

How many ways are there to map a database with Entity Framework in .NET?
I understand there is code-first and database-first (using .EDMX wizard for example).
Within the context of database-first, can I map my tables and relationships manually without using .EDMX? How many ways exist and which do you recommend?
Are there libraries for manual table mapping, which are the best?
I think there is not a best way, but maybe there is a way that fits best your needs.
I'll try to explain the ways you have, than you can choose the best for you.
On high level, there are two options:
DB first: you define the database and let a tool to create your model classes
Code first: you define your classes and let EF manage the tables for you
Mainly DB first is the best for:
Map an already existing database: in this situation your DB is already designed, so you have only to map entities
Your focus is the DB structure: in this situation, better if you design your DB as you want, then let a tool to map your entities
Code first is the best when you don't mind about the DB but you want to think about the object model. Of course, you can change how the DB is generated using data annotation or any other way EF gives you, but the focus for you has to be the object model.
Hi yes can can absolutely Map a database from EF. It is called scaffolding. What it does is it creates the database as models and required files for you.
Once you open the package manage or cmd you can type the following one-liner to scafford you database:
CMD:
dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer
Package Manager:
Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer
See the EF Core tutorial on it on the official windows website:
https://learn.microsoft.com/en-us/ef/core/managing-schemas/scaffolding?tabs=dotnet-core-cli
And for EF6 there is a great tutorial right here:
https://www.illucit.com/en/asp-net/entity-framework-7-code-first-migrations/
For full manual control with a Database-First project you can leverage a combination of convention, attributes, and/or entity configurations to configure the entities. Scaffolding I find works 90% of the time, but usually there will be some aspect of a production schema, especially where you don't have the flexibility to change the schema to make it more ORM-friendly, that scaffolding doesn't quite handle.
Also, if you're adopting something like bounded contexts (think DbContexts with fit-for-purpose mappings) and want to customize how tables/views map to entities, then it helps to be more explicit with the mapping. For example, for general entities I will map navigation properties, but in cases where I want raw performance over larger operations I will want to forgo declaring navigation properties and work strictly with FK columns. The less "mapping" a DbContext has to worry about and fewer entities it is tracking, the faster it performs.
Attributes: Here you declare your entity classes and use the appropriate attributes to describe the table, key, and other aspects such as column renames etc.
I.e.
[Table("tblOrders", "App")] // tblOrders table in App namespace
public class Order
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int OrderId { get; set; }
[Column("OrderNum")]
public string OrderNumber { get; set; }
public string OrderRef { get; set; }
[ForeignKey("Customer")]
public int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
}
This works for the 90-%ile of cases where you want to set up entities. For simple columns that you don't need to rename etc. you don't need to add attributes and leave it to convention.
Entity Configuration: The commonly referenced means of doing this is to use the DbContext's OnModelCreating override and use modelBuilder to configure the entities. For smaller system with a couple handfuls of entities this can be manageable, but for larger systems this can get rather bloated since everything ends up in one method, or a chain of method calls to break it up.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Order>()
.ToTable("tblOrders", "App")
.HasKey(x => x.OrderId)
.Property(x => x.OrderId)
.HasDatabaseGenerated(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Order>()
.Property(x => x.OrderNumber)
.HasColumnName("OrderNum);
modelBuilder.Entity<Order>()
.HasRequired(x => x.Customer)
.WithMany(x => x.Orders)
.HasForeignKey(x => x.CustomerId);
}
The lesser documented option is to leverage EntityTypeConfigration<TEntity> (IEntityTypeConfiguration<TEntity> in EF Core)
public class OrderConfiguration : EntityTypeConfiguration<Order>
{
public OrderConfiguration()
{
ToTable("tblOrders", "App");
HasKey(x => x.OrderId)
.Property(x => x.OrderId)
.HasDatabaseGenerated(DatabaseGeneratedOption.Identity);
Property(x => x.OrderNumber)
.HasColumnName("OrderNum");
HasRequired(x => x.Customer)
.WithMany(x => x.Orders)
.HasForeignKey(x => x.CustomerId);
}
}
From there the DbContext just needs to be initialized to load the entity type configurations. This is done in the OnModelCreating which you can do explicitly, or add all Configurations by assembly.
modelBuilder.Configurations.AddFromAssembly(GetType().Assembly);
Personally, I default to declaring EntityTypeConfigurations for all entities as I prefer to rely on convention as little as possible. Being explicit with the configuration means you have something to investigate and work with where a convention doesn't work the way you expect, and it allows you to declare mappings for things like ForeignKeys without declaring FK properties in the entities. (Highly recommended to avoid two sources of truth about a relationship, being the FK and the navigation property)
My projects will commonly have a .Data project where I will keep the Entities, DbContext, and Repositories for a project. The EntityTypeConfiguration instances I place under /Entities/Configuration. They could just as easily be housed in the entity class files, as internal members of the entity class itself, or nested under the Entity class. (I.e. using a plugin like NestIn)

Add id column in self referencing many-to-many table in entity framework

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

Entity Framework Inheritance and Relationships

I'm trying to implement TPH inheritance with Entity Framework 6 Code First and am having problems with a relationship from my inherited types.
My code is
public abstract class Base...
public class Inherited1 : Base
{
public virtual Type1 Rel { get; set; }
...
public class Inherited2 : Base
{
public virtual Type1 Rel {get;set;}
...
So the inherited types have the "same" relationship. The inheritance itself works fine, but the problem I'm having is that the relationship to the table Type1 will be added twice (logical...) and the other relationship is from Inherited2.Id to Type1.Id instead of Inherited2.Type1Id to Type1.Id that the first relationship is (correctly).
I'm not sure if I made any sense explaining this and with the partial code sample with changed type names, but I hope you got the point. Ask for more details if you need any.
I probably could implement this correctly with
UPDATE
I've created a sample Github repo to demonstrate the issue. Feel free to tell me what I'm doing wrong. https://github.com/antsim/EntityFrameworkTester
Try to use the following
1- if you want TPT
modelBuilder.Entity<Inherited1>()
.ToTable("Inherited1s")
.HasKey(x => x.YourKey)
.HasRequired(x=>Type1)
.WithMany()
.HasForeignKey(x=>Type1Id)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Inherited2>()
.ToTable("Inherited2s")
.HasKey(x => x.YourKey)
.HasRequired(x=>Type1)
.WithMany()
.HasForeignKey(x=>Type1Id)
.WillCascadeOnDelete(false);
2 - if you want TPH
modelBuilder.Entity<Base>()
.ToTable("YourTableName")
.HasRequired(m=>m.Type1)
.WithMany()
.HasForeignKey(m=>m.Type1Id)
.WillCascadeOnDelete(); // true or false as you want
for more details you might check this article
based on the sample you provided
Attachment and Document are inherited from File and you are using TPH which means One table will be created with a Discriminator field.
Document and FileContainer has a relation of type 0..1 which means a Foreign Key FileContainerId should be created in the Document hence in the File table
FileContainer and Attachment has a relation of type 0..n, then another nullable foreign key will be created in the table File
in the example you provided, I made the following changes
Add FileContainerId to the table Document
Add FileContainerAttachmentId to the table Attachment
The changes made on the TestContext was
modelBuilder.Entity<FileContainer>()
.HasOptional(x => x.Document)
.WithMany()
.HasForeignKey(t => t.DocumentId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Document>()
.HasRequired(t => t.FileContainer)
.WithMany()
.HasForeignKey(t => t.FileContainerId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Attachment>()
.HasRequired(t => t.FileContainer)
.WithMany()
.HasForeignKey(t => t.FileContainerAttachmentId)
.WillCascadeOnDelete(false);
the output was correct ( File table contains discriminator field in addition to two relations one for the document with the container and the other for the attachment with the container).
A better solution in my opinion is:
To add a class FileType ( Id, Name) with values Attachment, Document, and add it as a foreign key in File
To add only one relation 0..n between the FileContainer and File
To validate that only one record in the File of type document to same container
Hope this will help you

NHibernate On Legacy Database How To Tell NHibernate Which Is The Parent Table

I have two tables in a legacy database...
tblParentTable (int id, string specialIdentifier, ...)
tblChildTable (int id, string specialIdentifier, ...)
As you can see, an auto-incrementing int id has been added, but the child table is joined using the old string primary key (in fact, specialIdentifier is the primary key of tblParentTable, and the primary and foreign key on tblChildTable).
So I have created domain objects and Fluent NHibernate maps, but because of this odd schema, NHibernate thinks that it needs to save the tblChildTable record first, before it saves tblParentTable - this results in a foreign key constraint error.
How can I hint to NHibernate that tblParentTable is the parent and needs to be saved first?
Here is are the mappings...
public ParentMap()
{
Table("tblParentTable");
Id(x => x.Id).Column("id");
Map(x => x.SpecialIdentifier);
References(x => x.Child).Column("specialIdentifier");
}
public ChildMap()
{
Table("tblChildTable");
Id(x => x.Id).Column("id");
Map(x => x.SpecialIdentifier);
References(x => x.Child).Column("specialIdentifier");
}
Please feel free to ask for more information if you think I am missing something important.
Thanks
I don't use fluent; instead I create my mappings by creating the xml mapping files manually.
I believe that the 'inverse' property on the association allows you to specify the 'owner' (parent) of the association. Since I don't use fluent, I don't know how to specify that in your mapping, so I cannot give you an example.
Also, in Xml mapping, I'd use the 'property-ref' attribute to indicate that the 'specialIdentifier' is the column that is used by the relationship.
If you are looking to do this kind of mapping in Fluent NHibernate, there is a good article on it here:
http://wiki.fluentnhibernate.org/Fluent_mapping

is there a way to do a reverse lookup in nhibernate?

i have two tables:
Components
ComponentDependencies
ComponentDependencies has two columns: ComponentId and ComponentDependencyID. (both foreign keys into Id field of Component table.
i am using fluent nhiberate and i have my component object having:
public virtual IList<ComponentDependency> Dependencies { get; set; }
and in my ComponentMap class, i have nhibernate map:
HasMany(x => x.Dependencies)
.AsBag().Inverse();
So when i have a component object, i can see a list of its dependencies.
Is there anyway i can have an additional property have the "reverse" list. What i mean is that i want a property called "DependentOf" which is also a
IList<ComponentDependency>
which has all of the items where this current component is the dependent component in the relationship?
This looks like a bill-of-materials problem with Components having a many-to-many relationship to itself through the ComponentDependencies linking table. You can map both relationship directions by alternating which column is the parent key column:
HasManyToMany(x => x.Dependencies).Table("ComponentDependencies")
.ParentKeyColumn("ComponentId").ChildKeyColumn("ComponentDependencyId");
HasManyToMany(x => x.DependentOf).Table("ComponentDependencies")
.ParentKeyColumn("ComponentDependencyId").ChildKeyColumn("ComponentId");

Categories

Resources