I am trying to configure my model to an existing database, and am running into a problem. The previous developer modeled a one-to-one relationship using a join table. If I have the following classes and database structure below, how can I map this using code first?
public class Title {
public Property Property { get; set; }
}
public class Property {
public Title TitleInsurance { get; set; }
}
tbTitle
-TitleID = PK
tbPropertyToTitle
-TitleID - FK to tbTitle.TitleID
-PropertID - FK to tbProperty.PropertyID
tbProperty
-PropertyID = PK
Code in VB.Net here, but should be easy to translate. Mark primary keys with the Key data attribute. Entity Framework will automatically look for properties named Class + ID, i.e. tbTitleID to assign as primary keys, but since that isn't applicable here, we need the Key attribute.
Overridable properties denote Navigation Properties. In C#, this should be equivalent to Virtual properties. When this navigation property is accessed, Entity Framework will automatically look for valid foreign key relations, and populate the appropriate data.
For a one-to-one relationship, Entity Framework expects that your two tables share the same primary key, as shown by TitleID here.
Public Class tbTitle
<Key()>
Public Property TitleID As Integer
...
Public Overridable Property Property As tbProperty
End Class
Public Class tbProperty
<Key()>
Public Property TitleID As Integer
...
Public Overridable Property Title As tbTitle
End Class
Looking through the fluent API, I don't see any way to map one to one relations through a join table. You might be able to fake it by setting it up as a many to many but then you would need a bit of extra code to ensure that your relation collections only ever have one item in them.
Related
I'm making a Windows Service using Code First From Database, but my code is throwing the following exception. Where can I change Foreign Key configuration of this class, because it looks like that the columns are cross-referenced, the column usu_grpcom must refer codagp and usu_codemp must refer codemp.
e013agp_usu_titefol_Source_e013agp_usu_titefol_Target: : The types of
all properties in the Dependent Role of a referential constraint must
be the same as the corresponding property types in the Principal
Role. The type of property 'usu_grpcom' on entity 'usu_titefol' does
not match the type of property 'codemp' on entity 'e013agp' in the
referential constraint 'e013agp_usu_titefol'.
e013agp_usu_titefol_Source_e013agp_usu_titefol_Target: : The types of
all properties in the Dependent Role of a referential constraint must
be the same as the corresponding property types in the Principal
Role. The type of property 'usu_codemp' on entity 'usu_titefol' does
not match the type of property 'codagp' on entity 'e013agp' in the
referential constraint 'e013agp_usu_titefol'.
Better you should share the classes implementation for better understanding. I'm providing you code according to my understanding. You can use the similar code to solve your problem.
public class usu_titefol
{
public e013agp e013agp { get; set; }
[ForeignKey("codemp")]
[Required]
public int usu_grpcom { get; set; }
}
I'm trying to create a One-to-One relationship between two tables using a primary key and a unique key of the two tables (rather the primary keys).
The following is what I'd like to work.
// The principal end
public class A
{
// The primary Key
public int AId { get; set; }
// The navigation property
public virtual B B { get; set; }
}
// The dependent end
public class B
{
// The primary Key
public int BId { get; set; }
// The unique key
[Index(IsUnique = true)]
public int AId { get; set; }
// The navigation property
public virtual A A { get; set; }
}
But then I see this error:
Unable to determine the principal end of an association between the types 'A' and 'B'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
I'm quite sure a primarykey-uniquekey relationship is allowed in SQL Server. Looks like EF6 doesn't support it. EF Core 1.0 seems to, but it's not feasible to port to EF Core right now.
Why we need a need a relationship of this kind:
We have two tables A and B in production, but the one-to-one relationship, which should have been there is missing. The relationship is something we need so we can navigate from an A object to a B object with EF. Since both tables have values, we can't really make the primary key, the foreign key - we'll end up with incorrect data.
My approach to fixing this was to:
add a column
fill it with the correct A ids
make it unique
establish the 1-1 relationship
An alternate approach to fixing this is more than welcome.
This is possible with EF Core using Fluent API's .HasPrincipalKey() method. Unfortunately not supported in EF6 which is a shame as relationships over unique keys can essentially be treated the same as foreign key constrains so I'd imagine it would have been an easy addition.
Now that MS has forgot about EF6 and is focusing on EF Core, this will never happen. I really liked using the visual entity designers as it saved so much time. Looking at the thousand+ lines of code the EF Core DbContext scaffold generator spits out for me is discouraging to say the least. Sure, it's pretty when you're dealing with a demo project consisting of two cute tables but we all know this is never the case in the real world. The whole point of using an ORM is to save time but I'm not sure if having to manage thousands of lines of configuration code is any better. Just by two cents.
I have a class as
public class fooClass
{
[Key]
public virtual fooRefClass staff { get; set; }
public Int64 fooProp1{ get; set; }
public DateTime fooProp2{ get; set; }
}
when i do the migration it give me error as "no key defined" but i had added the key attonation already .My intention is to make the referenced entity "fooRefClass " as primary key as well as foreign key, i know there is a way by mentioning the attribute id of the referenced entity and writing the foreign-key annotate over there, but i want to deal with entity directly ,rather than id only, how can i attain this functionality ,please help me with the issue.
Since there seems to be confusion, I decided to write an answer as well.
With the class you defined, EF would expect a table like
fooClass(bigint fooRefClass_Id, bigint fooProp1, datetime fooProp2);
... which is not valid, because this has no key column (the key annotation on your navigation property does nothing, because you see, it won't appear in the table... it will just tell EF there is a relationship to this table, and because you didn't provide a FK, it creates one to create this relationship). You also can't create this relationship yourself in your current model, because you don't even have a FK... how would you access a property you know nothing about, just that it will be created at some point (usually upon model creating with first accessing the database).
You have to tell EF you want the property, that will be created, to also be a key, not only a foreign key. You can do this by simply creating the property yourself and telling EF you want to use this, for example (I'm not too familiar with Data Annotations, I usually use Fluent API, so please excuse maybe occuring errors)
[Key, Foreign Key(fooRefClass)]
public Int64 StaffId {get; set;}
Given the Model:
Public Class Customer
Property Id() As Guid
Property FirstName() As String
Property MiddleName() As String
Property LastName() As String
Property Addresses() As ICollection(Of Address)
End Class
Public Class Address
Property Id() As Guid
Property Name() As String
Property Street() As String
Property City() As String
Property Zip() As String
Public Property Customer() As Customer
End Class
Entity Framework 6 Code First has created a column called Customer_Id in my table Addresses. Now, I'd like to add a Property Customer_Id to my class Address that represents the existing foreign key relation:
Public Class Address
Property Id() As Guid
Property Name() As String
Property Street() As String
Property City() As String
Property Zip() As String
Public Property Customer() As Customer
//Added
Public Property Customer_Id() As Guid
End Class
Unfortunately this results in an InvalidOperationException while creating the DbContext saying:
The model backing the 'DataContext' context has changed since the database was created.
I tried different property names (with and without underscore, different casing). But still no luck. So, what is the correct way to add those properties subsequently without the need for migrations? I assume it's possible, because the model does not really change, I am only changing from an implicit declaration of a property to an explicit...
Update:
The responses show me, that I did not explain the problem very well. After some more reading I found the correct names now: I have an application which is installed several times at customer locations (therefore dropping and recreating the database is no option). Currently, it depends on Entity Framework's Independent Associations, but I want to have the Foreign Key in my entity as well (this is no change to the model, the foreign key is already there, but does not exist as a property in my entity, since this is currently only relying on the IA instead). I did not manage to add it without EF thinking my Database is outdated.
for me two ways :
drop table __MigrationHistory : that is have the new model runs, but forget migration functionalities
create a new db by changing the connection string of the application. Replace old __MigrationHistory by __MigrationHistory of the newly created db
Never tested the second solution, but it should work.
Before using any solution:
backup you db.
Before using first solution: are you sure you will never need migration functionalities ?
This exception is because you change your model. You have to set migration strategy. Please look at:
http://msdn.microsoft.com/en-us/data/jj591621#enabling
(edited)
First of all you have to remove that exception. Even if you didn't add any new column to your database your model has changed because you added new property to Address class. If you check your DB you will find dbo.__MigrationHistory table with Model column. Last (earliest) value from that column is used for checking that your model and DB are compatible. I'm not sure but I think that EF stores there binary serialized model. So the solution is - recreate DB or add migration (probably empty migration).
(edited)
When you want to set FK you can do this very simple by Data Annotations
// c# example
public class Address
{
...
public string CustomerId { get; set; }
[ForeignKey("CustomerId")]
public Customer Customer { get; set; }
}
or in fluent api
// c# example
modelBuilder.Entity<Address>()
.HasRequired(arg => arg.Customer)
.WithMany()
.HasForeignKey(arg => arg.CustomerId);
or look at:
http://weblogs.asp.net/manavi/archive/2011/05/01/associations-in-ef-4-1-code-first-part-5-one-to-one-foreign-key-associations.aspx
http://msdn.microsoft.com/en-us/data/hh134698.aspx
I have and EMDX created with Database first, i have followed the sample described here, so now i can map one entity to multiple tables in my database, and this is working fine.
But i need also to have the navigation properties that the FKs provide on the tables on this one entity, how could i achieve that?
I have two tables, on named Carteira and another named Ativo, in my EMDX i want to have the properties of Ativo also to be on Carteira, because they have an 0:1 relationship, so i have done this already and it is working! :) but i also want the navigation properties that are in the Ativo class to be on Carteira
Please see a sample describing the properties :
class Ativo
{
public string Id { get; set; }
public IList<Valor> Valores { get; set; }
}
class Carteira
{
public string AtivoID { get; set; }
public Ativo Ativo {get; set;}
}
So i would like to have something like
Carteira.Valores (and this should be infereed from Ativo).
Please note that i dont want to make this code manually using a partial class and acessing the navitation, i have already done this and i dont like this approach, it looks like this:
public partial class Carteira
{
public List<Valor> Valores
{
get
{
if (this.Ativo == null)
return null;
return this.Ativo.Valores;
}
}
}
I would like to know how to achieve this using the EMDX only, the same way that can be done for simple properties, is this possible?
For 0:1 to 1 relation,EF requires Foreign key to be same as Primary key on dependent table. So Ativo class must have Primary key of same name as AtivoID and that should be foreign key as well.
I managed to get the navigations working in 2 differente ways:
1 - Creating an 'Association' at the model (EMDX).
The associations work as if they were actual FKs, and since i already have the mapping collumns on both sides, it can be done by performing those steps:
Create a new Association at Carteira (second level class) that reflects the same properties of the FK present at Ativo (first level). When this is done, the navigation properties are created on both classes
2- Using Table-Per-Type Inheritance
In this specific scenario, the class could actually inherit from the other, and then take use of all of the navigations, for this to work i had to implement a TBT inheritance, altering the tables and adding "Conditional Mapping" to both tables (the concrete and the inherited) at the model (EDMX)