How do I use Fluent nHibernate to map a multi-table entity using a foreign key from the primary entity using an FK->PK relationship? - join

This is the basic example from hbm-style nhibernate.
http://ayende.com/blog/2327/multi-table-entities-in-nhibernate
public class Person
{
public int PersonId {get;set;}
public string Name {get;set;}
public string AddressStreetAddress {get;set;}
public string AddressZipCode {get;set;}
}
In the database, Person has an Id primary key, a name field, and an address foreign key. Address has its own primary key, a street address field and a zip code field.
The correct answer is "Don't do it.". Unfortunately I'm stuck with an entity object that exposes the Id and Name of another entity and those are used elsewhere still. At the moment, this object won't be persisted back to the database through nHibernate.
I think the way to do this is to use the address as the table of the entity and add the Person fields from the Join(). What are the consequences of doing this as an intermediate step in a change-over?

I think the way to do this is to use
the address as the table of the entity
and add the Person fields from the
Join(). What are the consequences of
doing this as an intermediate step in
a change-over?
This was a bad idea because the only Id you could map to is the Id of the address which can be shared between multiple persons.
Instead, add a private/protected property for Address to Person, map Address and reference the address using the following Fluent call.
References(Reveal.Member<Person, Address>("Address")).Column("address_id")
Then, you can use AddressStreetName and AddressZipCode to pass through to Address.StreetName and Address.Zipcode. After that, it's a simple matter of refactoring the rest of the system to be sane again.

Related

Entity Framework call best way to call a another api

Building an api around a db and as part of this we'll be calling another api and joining data in that api to the database for viewing but not storing the data in the current database. My question is if this.
In my data model I have
public class server
{
public Int32 ServerID {get;set;}
public string ServerName {get;set;}
...
}
If I add api columns with to the server object
public string ServerMemory
That of course returns and invalid column name because this is data from the api that is not in the database table.
I see a few options
Create a view within the database structure which has some blank columns and reference that within my data model.
Create another object within my data model and then reference it using virtual using something like the method mentioned here: https://jeremiahflaga.github.io/2020/02/16/entity-framework-6-error-invalid-column-name-_id/
Create another object and a cast to cast the Server object to this other object.
Is there another simpler way to reference a foreign field within an object in a data model?
Thank you.
I found this so anyone else who needs to add a column to a datamodel that does not exist in the database
using System.ComponentModel.DataAnnotations.Schema;
then you can use this:
[NotMapped]
public virtual string RoleDesc { get; set; }
Still curious if this is the best way. I guess that really revolves around your goals.

Entity framework 4 code first, use the same model to multiple tables?

Im using Entity Framework 4 with code first. I have a model and i want to be able to map this model to a different table in the database based on a configuration file.
Example model:
public class Statistic
{
[Key]
public int id { get; set; }
public string jobName { get; set; }
public DateTime date { get; set; }
public int pages { get; set; }
}
Each customer has a configuration file where the table name that should be used is specified. So each customer should then have its own table (in the same database) with the model above.
How can i do this with Entity Framework 4?
I tried this in my DbContext:
modelBuilder.Entity<Statistic>().ToTable(tabelName);
But what EF does when i use this is to change the existing table name to the new tableName, not creating and using a new one.
Thanks!
It is not possible. Each class can be mapped only once per mapping set (per context in common cases). Why? Because the access point to database is a DbSet (or ObjectSet in ObjectContext API) and it is simply created this way:
var set = dbContext.Set<Statistics>();
How should EF know which mapping of Statistics class should be used? It must know which mapping to use to query correct table and to save changes to correct table. You can probably argue that it could be defined as parameter but that would expose mapping details outside to upper layer - that is undesirable.
Edit:
If your application logic never needs access to more than one customer's statistics you can create mapping per customer dynamically. You need:
Create instance of DbModelBuilder and define mapping (or fill Configurations) - in this step you will provide the name of the table for current customer
Call Build method to get DbModel instance
Call Compile on DbModel instance to get DbCompiledModel instance
Cache compiled model somewhere. Model compilation is expensive operation and you need to do it only once per each customer (and per each application restart).
Pass compiled model to DbContext constructor and use that context instance to access data only for that customer
If you need to simultaneously access data for multiple customers you must do it through SQL.

Fluent Nhibernate HasMany to One Table from Several Tables

I have an entity/class/table which is referenced from several other entities, and I use Fluent NHibernate to handle the ORM for me. In a few instances, it's a simple reference where I can store the foreign key ID as a column and handle the reference in that simple way, but in a few other instances I need to reference a list of these items, and it needs done for at least three classes I can think of. You can assume this setup will be copied to handle the other classes' relationships.
Here's how the common entity looks (the one that is owned by several other entities in HasManys):
public class Student {
public virtual int Id {get; set;}
public virtual string Name {get; set;}
}
And, here's what the ShopCourse entity looks like:
public class ShopCourse {
public virtual int Id {get; set;}
public virtual int Name {get; set;}
public virtual IList<Student> Students {get; set;}
}
Imagine that a couple other classes I have, such as specific courses, can "own" several students. In order to maintain that relationship I must create a table in my database that tracks the foreign keys between the two (for each entity that references Student) - no entity needed for this intermediate table, and Fluent won't need to think of it unless I hand it the string name of the table itself:
Table: ShopCourseStudents
int - ShopCourseId
int - StudentId
Lastly, here are my mappings. You can assume that the entities themselves map out fine - things such as the naming scheme for the Id are resolved and working correctly. The issue lies when I attempt to initialize any entity that has a HasMany of Student:
//Inside a FluentlyConfigure().Mappings(m => m.AutoMappings.Add() call:
.Override<ShopCourse>(map => {
map.HasMany(x => x.Students)
.Table("ShopCourseStudents")
.KeyColumns.Add("ShopCourseId")
.KeyColumns.Add("StudentId")
.Cascade.All();
})
The issue is that when I attempt to load a list of ShopCourses I get the Fluent error:
Foreign key (ABC123AF9:Student [ShopCourseId, StudentId]) must have
same number of columns as the referenced primary key (ShopCourses
[Id])
I do not override Fluent's mapping of Student as it's straightforward. For the purpose of this example, Student doesn't need to know which ShopCourses it belongs to, or any of the other courses that may own that particular Student record.
This seems like I'm doing something basic, wrong - what is it, exactly? Much obliged in advance!
So, the issue was with the custom code that I re-use with my projects, apparently the piece written to handle the ManyToMany convention is mostly broken. What I was looking for here was a ManyToMany relationship, not HasMany. The issue I had was that my code was forcing a reference on the child object (in this example, Student) to the parent, which I do not need and only complicates things. Removing that, and my ManyToMany then works:
.Override<ShopCourse>(map => {
map.HasManyToMany(x => x.Students)
.Table("ShopCourseStudents")
.ParentKeyColumn("ShopCourseId")
.ChildKeyColumn("StudentId")
.Cascade.All()

Entity Framework: Map Foreign Key without Navigation Property?

Motivation : My EF4.1 DbContext is saving Entities in the wrong order
Reason : Lack of navigation properties on my models
How I want to fix it :
I want to set up foreign key relationships in my DbContext. The catch is that my entity objects have no navigation properties (I'm using it to populate a web service and then firing DTO objects over to my application).
The classes below would be an example. In MinorClass, I want to configure my context so that it knows MajorClassID is a foreign key. The articles I've been finding on the internet on how to explicitly define Foreign Keys involve using navigational properties, which my objects dont have.
Is there a way to map this relationship?
public class MinorClass
{
public Guid ID {get;set:}
public Guid MajorClassID {get;set;} // foreign key
public string Name {get;set;}
}
public class MajorClass
{
public Guid ID {get;set;}
public string Name {get;set;}
}
Navigation property is primary construct whereas foreign key is helper (imho wrong helper). EF recognizes ordering of DB commands by relationships which are defined by navigation properties. You cannot define relation just by foreign key. You need navigation property on at least one side of the relation.

single entity for different tables

I have same type of tables
ProductCodeTable, CountrycodeTable etc
All have key, value as their fields
When I use entity frame work,
Can I have a single entity for all these tables such that I can formulate different queries to get data from different tables?
You can create a base class for all of them and create sub class for each entity
public abstract class LookUpEntity
{
[Key]
public int Key { get; set; }
[Required]
public string Value { get; set; }
}
[Table("ProductCodeTable")]
public class ProductCode : LookUpEntity
{
}
This way you can model the relationships also and later if you wanted to add specific properties to those look up entities with out affecting other entities.
You can create a view with a Union of all tables like this:
create view AllKeyTables as
SELECT 'Product' as table, Productkey as Key, nameProduct as name
FROM ProductCodeTable
UNION
SELECT 'Country' as table, CountryISO as key, CountryName as name
FROM CountrycodeTable
UNION
...
Then update EF model and check 'table' and 'key' fields as Entity Primary Key.
Next question you will do is: 'How can I make a relation between this Entity and existing Entities?' The answer is 'you can't because EF is not able to join Entities between other fields than primary key'. Then, before implement this solution, be sure that this is you are looking for.
EF supports this only if you model it as inheritance (#Eranga showed it in code-first approach). You will have single base entity and derived entity for each table so you will not avoid having different type for each table. Otherwise the answer is no.
Inheritance will put additional requirements on data in your tables. For example Ids will have to be unique among all tables. So if ProductTableCode will have record with Id 1, CountryCodeTable (and any other code table) mustn't have record with Id 1.
Also inheritance in EF can produce nasty and very poorly performing queries.

Resources