I have a question related to the Fluent NHibernate. I can not describe the schema mapping one entity to multiple tables. There is the following structure of the database:
Create table CeTypes (Id int not null PRIMARY KEY, Name nvarchar(100) not null)
Create table CeValues (Id int not null PRIMARY KEY, Name nvarchar(100) not null)
Create table Ces (Id int not null PRIMARY KEY, CeType_id int not null FOREIGN KEY REFERENCES CeTypes(Id), CeValue_id int not null FOREIGN KEY REFERENCES CeTypes(Id))
there is the following entity:
public class Ce
{
public virtual int Id { get; set; }
public virtual string Type { get; set; }
public virtual string Value { get; set; }
}
CeType, CeValue entities in the domain and there is no. I do not know how to describe the mapping Ce entity.
Tried to describe:
public class CeMap : ClassMap<Ce>
{
public CeMap()
{
Table("Ces");
Id(c => c.Id);
Join("CeTypes", m => m.Map(ce => ce.Type).Column("Name"));
Join("CeValues", m => m.Map(ce => ce.Value).Column("Name"));
}
}
But with such a scheme CeType, CeValue tables should have a field Ce_id. How can I describe scheme mapping under the current structure of the database?
I tried doing the same thing when I first started using nHibernate and couldn't find a way to do it. I actually don't believe that you can map multiple tables to a single object. Usually you would have one entity per table. Each entity will be mapped to their table and would have references/hasmany links between them.
You'll probably find that having one entity per table is better in the long run as well because it allows for simpler mapping to the database.
Related
To describe what I want: assume I have a table User in SQL Server, which contains the primary key field, and two fields that refer back to the same table using foreign keys.
CREATE TABLE [User] (
ID INT IDENTITY(1, 1) NOT NULL,
-- other properties omitted for brevity
CreatedByUserID INT NOT NULL,
LastModifiedByUserID INT NOT NULL,
CONSTRAINT PK_User PRIMARY KEY (ID),
CONSTRAINT FK_User_CreatedByUser FOREIGN KEY (CreatedByUserID) REFERENCES User
(ID),
CONSTRAINT FK_User_LastModifiedByUser FOREIGN KEY (LastModifiedByUserID) REFERENCES User (ID),
)
I can setup the "root" user by executing the following SQL:
INSERT [User] (CreatedByUserID, LastModifiedByUserID) VALUES (1, 1)
SQL Server doesn't throw any errors.
Now, if I try to create the same table using Entity Framework Code First, I get mixed results:
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[ForeignKey(nameof(CreatedByUser))]
public int CreatedByUserID { get; set; }
//[ForeignKey(nameof(ModifiedByUser))]
//public int ModifiedByUserID { get; set; }
public virtual User CreatedByUser { get; set; }
//public virtual User ModifiedByUser { get; set; }
}
This works as shown, but when I uncomment the ModifiedByUser* lines then I get a variety of "Multiplicity is not valid in Role" errors.
I've tried converting my annotation-driven class to a fluent-style configuration, but I have no luck when I run Add-Migration: there's always some error that crops up for some combination of configuration methods, and I never seem able to specify the CreatedByUserID or LastModifiedByUserID column names.
user.HasRequired(x => x.CreatedBy);
//.WithRequiredPrincipal();
user.HasRequired(x => x.LastModifiedBy);
//.WithRequiredPrincipal();
Am I trying to do something that's forbidden by Entity Framework? Or have I missed a line or two of configuration? How can I use EF to recreate the table structure shown at the top of this post?
EDIT:
The same pattern works just fine for a number of other entities in the model: for example a WorkItem can have both CreatedByUser and ModifiedByUser; the problem only seems to arise when the foreign keys refer back to an entity of the same type as their enclosing type.
I want to create 3 tables based on 3 entities using code-first and fluent API. I am using Entity Framework version 6. The join table needs a 3-column primary key and additional columns.
My question: how can I use code-first with C# Fluent API to create/map the 3-column primary key for the PatientTreatment table? Thank you.
Details of the 3-column primary key for the join table { PatentId, TreatmentId , TreatmentDate }. The values of PatentId and TreatmentId are fetched from the other 2 entities (tables) while the value of TreatmentDate is entered manually (e.g. C# code or T-SQL script like calling getdate() function).
Details of the 3 entities:
public class Patient {
public long PatentId {get; set;} // database created using Identity
...
}
public class Treatment {
public long TreatmentId {get; set;} // database created using Identity
...
}
And the join table (entity)
public class PatientTreatment
{
public long PatentId {get; set;} // part of the primary key from the Patient entity
public long TreatmentId {get; set;} // part of the primary key from the Treatment entity
public DateTime TreatmentDate {get; set;} // part of the primary key but its value is from C# code or from T-SQL script, not from other entity (table)
// other fields ...
}
You can't model this as a many-to-many association in which the PatientTreatment class is hidden, which is what is usually referred to as many-to-many in Entity Framework mapping.
But you didn't intend to do that, as is apparent from the explicit PatientTreatment class you show. So it's just a matter of modeling it correctly.
In the OnModelCreating override of your DbContext subclass, setup the mapping like so:
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Entity<PatientTreatment>()
.HasKey(x => new { x.PatientId, x.TreatmentId, x.TreatmentDate });
mb.Entity<Patient>().HasMany(p => p.PatientTreatments)
.WithRequired().HasForeignKey(x => x.PatientId);
mb.Entity<Treatment>().HasMany(t => t.PatientTreatments)
.WithRequired().HasForeignKey(x => x.TreatmentId);
base.OnModelCreating(mb);
}
I think this line HasKey(x => new { x.PatientId, x.TreatmentId, x.TreatmentDate }) is what you were looking for mainly.
I Just Serch it in stackoverflow
It's not possible to create a many-to-many relationship with a
customized join table. In a many-to-many relationship EF manages the
join table internally and hidden. It's a table without an Entity class
in your model. To work with such a join table with additional
properties you will have to create actually two one-to-many
relationships
check this many to many with extra column
Is it possible to flatten a two-table relationships into a single entity in Entity Framework?
Specifically, (simplified for example) given the following two tables that define a 1-1 relationship
create table Foo
(
Id int not null identity (1, 1)
constraint PK_Foo_Id primary key (Id),
Name nvarchar(64) not null,
BarId int not null
constraint FK_Bar_Foo foreign key (BarId) references Bar (Id)
)
create table Bar
(
Id int not null identity (1, 1)
constraint PK_Bar_Id primary key (Id),
Value nvarchar(max) not null
)
I can easily map this to entities like this
public class Foo
{
public int Id { get; set;}
public string Name { get; set;}
public Bar Bar { get; set;}
}
public class Bar
{
public int Id { get; set;}
public string Value { get; set;}
}
But what I would like to map to a single flattened entity
public class FlatFoo
{
public int Id { get; set;}
public string Name { get; set;}
public string Value { get; set;}
}
Notice that only one field from table Bar is mapped to FlatFoo
Notes
The actual tables are larger.
Since the text value in Bar can get large it would fill index pages quickly, so there are two tables for quicker index searches against Foo.Id and Foo.Name.
I have looked into Split Entities, but it required both tables have the same primary key.
I have looked at Complex Types but it works in the opposite manner taking a flat table and splitting into composite entities.
I am looking to use the Fluent API to perform the mapping.
Can you provide any help in flattening the mapping between two tables and a single entity?
Update
Yes, views will work to get a flat entity, but then I am not mapping from tables to entity. Likewise, from the other side, I know it is possible to map to non-public composition and expose the property that way. But, I am more interested in learning if EF fluent API is flexible enough to handle the mapping directly than I am in solving a particular issue.
Unfortunately, there is considerable push-back here (at work) to any suggestion of adding anything other than tables to a database (something as basic as views included). It is typically pointed out that doing so adds additional point of maintenance, increases training for support, adds complexity for basic CRUD and other excuses for not learning the tools available. It is silly at best, but it is something I have to deal with. :(
So, as a point of learning for me, is it possible to do this seemingly basic task of directly mapping fields from two arbitrary tables into one entity using EF, fluent API preferred?
Entity Framework doesn't provide a way to map one entity to two tables and then cherry pick from the columns in the way you describe unless the tables share a common key. So as mentioned in the comments, the simplest solution is to create a View and map the entity to that.
public class FlatFooMap : EntityTypeConfiguration<FlatFoo>
{
public FlatFooMap ()
{
ToTable("vwFlatFoo");
HasKey(t => t.Id);
}
}
I can't find an answer by searching through SO questions and by Googling around.
I have a very simple structure:
public class Employee
{
property int Id { get; set; }
property int Name { get; set; }
}
public class Developer : Employee
{
property string Level { get; set; }
}
and I have two tables for this domain model:
create table Employees
(
Id int not null primary key identity(1, 1),
Name nvarchar(100) not null
)
create table Developers
(
Id int not null primary key,
Level nvarchar(100)
)
alter table Developers
add constraint FK_Developers_Employees
foreign key ([Id]) references Employees ([Id])
This C# model and SQL Server database schema can not be changed. The scenario is:
First add an employee (One-employee)
This employee is not a developer yet (One-employee-to-Zero-developer)
Then promote that employee to a developer (One-employee-to-One-developer)
How should I configure my Context class? I would also appreciate sample code for this scenario.
You can not do this as simple as it seems. You have to delete the first entity from context, clone it in a new object -Developer here-, and add the new one to the context.
var emp = _context.Employees.Find(id);
_context.Delete(emp);
var dev = new Developer(/* clone from emp */);
_context.Developers.Add(dev);
_context.SaveChanges();
Which will change the Id of employee. However, if you want to avoid this (changing Id), you have to use raw SQL - e.g. calling a stored procedure - to add a row to Developers and reload the context.
Another option is to set Id column by custom, which as you mentioned in Q, it's not possible to change the scheme. So ignore it.
In Linq to SQL I could specify a relationship that didn't have to depend on the foreign keys and pks existing in the database, useful for creating composite relationships like this:
public class Equipment_CableNormalised
{
...
[Association(ThisKey = "EquipmentId,PortNumber", OtherKey = "EquipmentId,PortNumber", IsForeignKey = false)]
public List<EquipmentPort> EquipmentPorts
{
get; set;
}
}
This then generated the sql similar to " .. join EquipmentPorts EP on EP.EquipmentId = blah and EP.PortNumber = Blah".
Can I do the same sort of thing in EF4.1 (using annotations or fluent api)? I know you can specify composite keys and use the [Keys] and [ForeignKeys] attributes, but this relationship doesn't map to keys...
How does the sample relation from your code works? I expect that EquipementId must be either PK or unique key (not supported in both L2S and EF) on one side because otherwise the relation could not exist (both one-to-one and one-to-many demands unique principal). Once it is PK on one side the port number is redundant.
Code first allows only mapping to keys. If you have existing database you can cheat it in your model and map new relations in the same way as you would map existing but you still have to follow simple rule - properties in principal are primary keys, properties in dependent entity are mapped as foreign keys.
If you want EF to generate DB for you, you will always have all relations in the database.
Use HasKey http://www.ienablemuch.com/2011/06/mapping-class-to-database-view-with.html
Either use HasKey, put this on OnModelCreating
modelBuilder.Entity<SalesOnEachCountry>().HasKey(x => new { x.CountryId, x.OrYear });
Or use Key Column Order
public class SalesOnEachCountry
{
[Key, Column(Order=0)] public int CountryId { get; set; }
public string CountryName { get; set; }
[Key, Column(Order=1)] public int OrYear { get; set; }
public long SalesCount { get; set; }
public decimal TotalSales { get; set; }
}
Regarding your question about foreign key, I haven't yet tried the pure code(OnModelCreating) approach, perhaps you can just put two ForeignKey attribute on child class itself, might need to put Column Order too.
This could be the answer composite key as foreign key
That answer confirms my hunch that you could put two ForeignKey attributes on child class itself.