Entity Framework Code First - Navigation property on Composite Primaty Key - entity-framework

Firebird 2.5
Entity Framework 5
FirebirdClientDll 3.0.0.0
Hi, I'm trying to access my legacy database with the Entity Framework (Code First).
I got the problem that the database does not use foreign keys...
public class CUSTOMERS
{
public int CUSTOMERID { get; set; }
public string NAME{ get; set; }
}
public class INVOICES
{
public int INVOICEID{ get; set; }
public int CUSTOMERID{ get; set; }
public virtual CUSTOMERS CUSTOMERS { get; set; }
}
public class INVOICEContext : DbContext
{
public DbSet<CUSTOMERS> CUSTOMERS{ get; set; }
public DbSet<INVOICES> INVOICES{ get; set; }
public INVOICEContext(DbConnection connectionString) : base(connectionString, false)
{
Database.SetInitializer<INVOICEContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
/*modelBuilder.Entity<INVOICES>().HasRequired(b => b.CUSTOMERS)
.WithMany()
.Map(p => p.MapKey("INVOICEID"));*/ //Doesn't work because INVOICEID is defined
modelBuilder.Entity<INVOICES>().HasKey(a => new { a.INVOICEID, a.CUSTOMERID});
modelBuilder.Entity<CUSTOMERS>().HasKey(a => new { a.CUSTOMERID });
base.OnModelCreating(modelBuilder);
}
}
Normally I could remove the property CUSTOMERID from the class INVOICES, but in this case it is part of the primary key...
I found many threads which suggested to use IsIndependent, but it seems to be removed from the Entity Framework 5 (or 4.1).
I hope you can understand my poor English and maybe give me a hint what I'm doing wrong ^^

I don't know what you mean with "the database does not use foreign keys". So, maybe the following is not the answer you are looking for. But I'd say that you can use your relationship mapping that is commented out in your code if you replace ...MapKey... by HasForeignKey and use CUSTOMERID instead of INVOICEID as the foreign key property:
modelBuilder.Entity<INVOICES>()
.HasRequired(b => b.CUSTOMERS)
.WithMany()
.HasForeignKey(b => b.CUSTOMERID);
The model and the rest of the mapping is fine in my opinion. Your relationship is an identifying relationship (that means that the foreign key is part of a composite primary key) which is a valid mapping with Entity Framework.

Try this ...
modelBuilder.Entity<INVOICES>()
.HasRequired(i => i.CUSTOMERS)
.WithMany()
.HasForeignKey(i => i.CUSTOMERID);

Related

Map Existing Entity with Existing Table in Entity FrameWork

Is it possible to map existing tables with existing Entities in Entity frame work as like NHibernate doing.
For example. I have entity as
public class User
{
public Int64 userId { set; get; }
public String Username { set; get; }
public Int64 RoleId { set; get; }
}
public class Role
{
public Int64 roleId { set; get; }
public String roleName { set; get; }
public IList<User> listUser { set; get; }
}
I have Table as
Users with id,name,roleId
Roles with id,name.
Now I want to map both using XML files. Is it possible to map exiting tables with exiting Entities.
You have a few options:
1) Manage your mapping via the database first edmx file (see http://www.asp.net/mvc/tutorials/mvc-5/database-first-development/creating-the-web-application)
2) Start with the database first approach then move over to a code first like approach using the fluent api (see http://agilenet.wordpress.com/2011/04/11/entity-framework-4-1-rc-with-an-existing-database/)
Usual way of mapping in EF is data annotation attributes or fluent mapping (actually with NHibernate fluent mapping is also better, because it gives you compile-time checks). So, here is fluent mapping for your classes:
public class UserMapping : EntityTypeConfiguration<User>
{
public UserMapping()
{
ToTable("Users"); // Not necessary, EF will use this mapping by default
HasKey(u => u.userId);
Property(u => u.userId).HasColumnName("id");
Property(u => u.Username).HasColumnName("name");
Property(u => u.RoleId).HasColumnName("roleId");
}
}
public class RoleMapping : EntityTypeConfiguration<Role>
{
public RoleMapping()
{
ToTable("Roles"); // Not necessary, EF will use this mapping by default
HasKey(r => r.roleId);
Property(r => r.roleId).HasColumnName("id");
Property(r => r.roleName).HasColumnName("name");
HasMany(r => r.listUser)
.WithRequired()
.HasForeignKey(u => u.RoleId);
}
}
Just provide these mappings to your DbContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserMapping());
modelBuilder.Configurations.Add(new RoleMapping());
base.OnModelCreating(modelBuilder);
}
I suggest you to read MSDN article Configuring/Mapping Properties and Types with the Fluent API.
Side note - another article to read is Naming Guidelines, especially its Capitalization Styles part.

Will one-to-one foreign key associations be supported in EF v-Next?

I have entities A and B and I want to create 2 distinct 1-1 associations between A and B. A should play the role as principal. Like this:
public class A
{
public int Id {get; set;}
public B B1 {get; set;}
public B B2 {get; set;}
}
public class B
{
public int Id {get; set;}
}
Since EF does not support one-to-one foreign key associations I cannot create a working model/database with EF. To my this sounds like a serious limitation. Are there any plans to support such associations in an upcoming version of EF?
What is the best workaround for to get this working. I know about creating two one-2-many associations. However, that would make B the principal and gives me problems with cascading deletes.
Thanks for replying to my question. Below is an example of what I want to do, i.e., create two (or more) 1-to-1 associations between an entity A and another entity B. Is this something that EF could support in vNext, or else, why would it be a bad idea?
Thanks again,
Merijn
public class A
{
public int Id {get; set;}
public int B1_Id {get; set;}
public B B1 {get; set;}
public int B2_Id {get; set;}
public B B2 {get; set;}
}
public class B
{
public int Id {get; set;}
}
public class SampleContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<A>().HasKey(c => c.Id);
modelBuilder.Entity<B>().HasKey(c => c.Id);
modelBuilder.Entity<A>().HasRequired(c => c.B1).WihOptional().ForeignKey(x=>x.B1_Id);
modelBuilder.Entity<A>().HasRequired(c => c.B2).WihOptional().ForeignKey(x=>x.B2_Id);
}
}
If "v-Next" is Entity Framework 6, then no, it apparently won't support one-to-one foreign key associations, as you can see on the roadmap for all features planned for EF 6.
You can also see that Unique Constraint support is not on the roadmap and still marked as "Under Review" on UserVoice.
Because a one-to-one foreign key association is basically a one-to-many association with a unique constraint on the foreign key column I would expect that one-to-one FK associations won't be implemented before Unique Constraint support is available. It's especially required if you want that A is the principal in your two relationships. Currently EF does not support relationships where the principal's key is not the primary key but some column with unique constraint.
In this blog post the feature is described and mentioned that it is "postponed", so let's hope for EF 7.
Perhaps it is a terminology issue.
In Code first EF, EF doesnt allow you to have 1:1 relationships with Principal and Dependent both with foreign keys to each other
or with the dependent having its own primary key unrelated to Principal.
With your example it looks like that it is a case of 2 navigation properties required.
And strictly speaking it is not 1:1. since you have 2 relationships to the same table.
you have 2 relationships of type 1:1.. EF sees this as many to 1.
If you have a true 1:1 relationship, EF will want the dependent to have the same Primary Key as the primary.
You can define Multiple NAVIGATION properties on Both Principle and dependent, which result in indexes.
So you may wish to investigate Many to 1 configurations
If you want the Primary to have an OPTINAL Foreign Key at DB level, You would need to ADD this FK later during migration or with script.
But arguably this is best seen as business logic/rule check rather than an OPTIONAL FK on principal.
So yes there are limitations in matching exactly what is possible on the DB.
But it is questionable is actually necessary in a code first scenario.
Neat trick here btw is to model in DB exactly what you want on Code first.
There use the EF Powertool nuget to reerse engineer Codefirst from DB.
EG mini DB with just the desired table relationships.
make a new project in Solution. Install Entity Framework Powertools.
Then use right click option in new project to "reverse engineer code first from DB".
It shows how to build that in code first if it can.... :-)
What I think you wanted to achieve... see code sample (sorry if I misunderstood the point your are making) code should execute if NUGET is loaded
using System.Data.Entity;
namespace EF_DEMO
{
class FK121
{
public static void ENTRYfk121(string[] args)
{
var ctx = new Context121();
ctx.Database.Create();
System.Console.ReadKey();
}
}
public class Main
{
public int MainId { get; set; }
public string BlaMain { set; get; }
public int? Sub1Id { set; get; } // Must be nullable since we want to use EF foreign key
public int? Sub2Id { set; get; } // Must be nullable since we want to use EF foreign key
public virtual Sub Sub1 { get; set; } // Reverse navigation
public virtual Sub Sub2 { get; set; } // Reverse navigation
// you may also need
public virtual ICollection<Sub> Subs { get; set; }
}
public class Sub
{
public int SubId { get; set; } // Deliberately DIFFERENT KEY TO MAIN.... not 1:1 so this is possible
public string blasub { set; get; }
public int MainId { set; get; } //set in API , this the FK
public virtual Main Main { get; set; } // van to Principal
}
public class Context121 : DbContext
{
static Context121()
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Context121>());
}
public Context121()
: base("Name=Demo") { } // webconfig required to match
public DbSet<Main> Mains { get; set; }
public DbSet<Sub> Subs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Main>().HasKey(t => t.MainId)
.HasOptional(t => t.Sub1)
.WithMany()
.HasForeignKey(t=>t.Sub1Id) ; // tell EF the field is in POCO, use this please, otherwise it will create it.
modelBuilder.Entity<Main>()
.HasOptional(t => t.Sub2).WithMany()
.HasForeignKey(t=>t.Sub2Id);
modelBuilder.Entity<Sub>()
.HasKey(t => t.SubId)
.HasRequired(q => q.Main)
.WithMany()
.HasForeignKey(t => t.MainId);
}
}
}
WEBCONFIG....
<connectionStrings>
<add name="Demo" connectionString="Data Source=localhost;Initial Catalog=Demo;Integrated Security=True;MultipleActiveResultSets=True;App=EntityFramework"
providerName="System.Data.SqlClient" />
</connectionStrings>
Explain what problem do you need to resolve? This is sample of one-to-one mapping in EF 5.0
class Program
{
static void Main(string[] args)
{
using (var context = new SampleContext())
{
var mainEntity = new MainEntity();
mainEntity.DetailEntity = new DetailEntity();
context.SaveChanges();
}
}
}
public class SampleContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MainEntity>().HasKey(c => c.Id);
modelBuilder.Entity<DetailEntity>().HasKey(c => c.Id);
modelBuilder.Entity<MainEntity>().HasOptional(c => c.DetailEntity).WithRequired(p => p.MainEntity);
modelBuilder.Entity<DetailEntity>().HasRequired(c => c.MainEntity).WithOptional(p => p.DetailEntity);
}
public virtual DbSet<MainEntity> MainEntities { get; set; }
public virtual DbSet<DetailEntity> DetailEntities { get; set; }
}
public class MainEntity
{
public int Id { get; set; }
public DetailEntity DetailEntity { get; set; }
}
public class DetailEntity
{
public int Id { get; set; }
public MainEntity MainEntity { get; set; }
}

EF 4.1 Code First ModelBuilder HasForeignKey for One to One Relationships

Very simply I am using Entity Framework 4.1 code first and I would like to replace my [ForeignKey(..)] attributes with fluent calls on modelBuilder instead. Something similar to WithRequired(..) and HasForeignKey(..) below which tie an explicit foreign key property (CreatedBySessionId) together with the associated navigation property (CreatedBySession). But I would like to do this for a one to one relationsip instead of a one to many:
modelBuilder.Entity<..>().HasMany(..).WithRequired(x => x.CreatedBySession).HasForeignKey(x => x.CreatedBySessionId)
A more concrete example is below. This works quite happily with the [ForeignKey(..)] attribute but I'd like to do away with it and configure it purely on modelbuilder.
public class VendorApplication
{
public int VendorApplicationId { get; set; }
public int CreatedBySessionId { get; set; }
public virtual Session CreatedBySession { get; set; }
}
public class Session
{
public int SessionId { get; set; }
[ForeignKey("CurrentApplication")]
public int? CurrentApplicationId { get; set; }
public virtual VendorApplication CurrentApplication { get; set; }
public virtual ICollection<VendorApplication> Applications { get; set; }
}
public class MyDataContext: DbContext
{
public IDbSet<VendorApplication> Applications { get; set; }
public IDbSet<Session> Sessions { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Session>().HasMany(x => x.Applications).WithRequired(x => x.CreatedBySession).HasForeignKey(x => x.CreatedBySessionId).WillCascadeOnDelete(false);
// Note: We have to turn off Cascade delete on Session <-> VendorApplication relationship so that SQL doesn't complain about cyclic cascading deletes
}
}
Here a Session can be responsible for creating many VendorApplications (Session.Applications), but a Session is working on at most one VendorApplication at a time (Session.CurrentApplication). I would like to tie the CurrentApplicationId property with the CurrentApplication navigation property in modelBuilder instead of via the [ForeignKey(..)] attribute.
Things I've Tried
When you remove the [ForeignKey(..)] attribute the CurrentApplication property generates a CurrentApplication_VendorApplicationId column in the database which is not tied to the CurrentApplicationId column.
I've tried explicitly mapping the relationship using the CurrentApplicationId column name as below, but obviously this generates an error because the database column name "CurrentApplicationId" is already being used by the property Session.CurrentApplicationId:
modelBuilder.Entity<Session>().HasOptional(x => x.CurrentApplication).WithOptionalDependent().Map(config => config.MapKey("CurrentApplicationId"));
It feels like I'm missing something very obvious here since all I want to do is perform the same operation that [ForeignKey(..)] does but within the model builder. Or is it a case that this is bad practise and was explicitly left out?
You need to map the relationship as one-to-many and omit the collection property in the relationship.
modelBuilder.Entity<Session>()
.HasOptional(x => x.CurrentApplication)
.WithMany()
.HasForeignKey(x => x.CurrentApplicationId)

Specifying Foreign Key Entity Framework Code First, Fluent Api

I have a question about defining Foreign Key in EF Code First Fluent API.
I have a scenario like this:
Two class Person and Car. In my scenario Car can have assign Person or not (one or zero relationship).
Code:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public Person Person { get; set; }
public int? PPPPP { get; set; }
}
class TestContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Car> Cars { get; set; }
public TestContext(string connectionString) : base(connectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasOptional(x => x.Person)
.WithMany()
.HasForeignKey(x => x.PPPPP)
.WillCascadeOnDelete(true);
base.OnModelCreating(modelBuilder);
}
}
In my sample I want to rename foreign key PersonId to PPPPP. In my mapping I say:
modelBuilder.Entity<Car>()
.HasOptional(x => x.Person)
.WithMany()
.HasForeignKey(x => x.PPPPP)
.WillCascadeOnDelete(true);
But my relationship is one to zero and I'm afraid I do mistake using WithMany method, but EF generate database with proper mappings, and everything works well.
Please say if I'm wrong in my Fluent API code or it's good way to do like now is done.
Thanks for help.
I do not see a problem with the use of fluent API here. If you do not want the collection navigational property(ie: Cars) on the Person class you can use the argument less WithMany method.

EF4 CTP5 self-referencing hierarchical entity mapping

Okay, this should be really easy, but I've been tearing my hair out. Here's my POCO (which has to do with machine parts, so a part can be contained within a parent part):
public class Part
{
public int ID { get; set; }
public string Name { get; set; }
public Part ParentPart { get; set; }
}
When the database table is created, the column names are "ID", "Name", and "PartID". How do I change the name of that last column to "ParentPartID"?
Basically, you want to rename the foreign key in an Independent Association and this is the fluent API code that will do it:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Part>()
.HasOptional(p => p.ParentPart)
.WithMany()
.IsIndependent()
.Map(m => m.MapKey(p => p.ID, "ParentPartID"));
}
However, due to a bug in CTP5, this code throw as exception in self referencing associations (which is your association type). The workaround would be to change your association to a Foreign Key Association as follows:
public class Part
{
public int ID { get; set; }
public string Name { get; set; }
public int ParentPartID { get; set; }
[ForeignKey("ParentPartID")]
public Part ParentPart { get; set; }
}