I have a table of Recipes. Each Recipe has one and only one row in table RecipeMetadata, which contains various data about the recipe that I don't want to store in the Recipes table for various reasons. Thus, Recipes and RecipeMetadata have a one-to-one mapping. My Recipes table is as follows:
public partial class RecipesMap : ClassMap<Recipes>
{
public RecipesMap()
{
Id(x => x.RecipeId);
// Map() various columns here
HasMany(x => x.Ingredients).KeyColumn("RecipeId");
HasOne(x => x.Metadata);
}
}
And here's my RecipeMetadata table:
public partial class RecipeMetadataMap : ClassMap<RecipeMetadata>
{
public RecipeMetadataMap()
{
Id(x => x.RecipeMetadataId);
// Map() various columns here
References<Recipes>(x => x.Recipe).Column("RecipeId").Not.Nullable();
}
}
However, when I load a Recipe and access the Metadata property, it attempts to find a row in RecipeMetadata where Recipes.RecipeId = RecipeMetadata.RecipeMetadataId. In other words, it does the join using the primary keys on both tables.
With my table schema, RecipeMetadataId is a key unique only to that table, and has nothing to do with RecipeId. RecipeMetadata has another column, also called RecipeId which has a foreign key constraint on `Recipes. The JOIN should work as:
Recipes.RecipeId = RecipeMetadata.RecipeId
My Questions:
Am I wrong for wanting RecipeMetadata to have its own unique ID, and to use a separate column to link this to Recipes? Obviously, I have a FK constraint as well as a unique index on RecipeMetadata.RecipeId so there's no perf impact. Yes, there's some extra bytes on the disk for storing an arguably unnecessary ID on this table.
I've never seen a table whose primary key also has a foreign key constraint on another table. Is this legit practice? It seems to be the way nHibernate prefers to behave by default. Should I give in and let it have its way?
Provided I don't want to change the database (Though I can be convinced to do so if given a legitimate reason), how can I create the desired one-to-one mapping with this model?
NHibernate has a strict definition of one-to-one relationships. Strict but fair. In NHibernate one-to-one relationship means that the a row in table A always has a matching row in table B.
Right or wrong, that won't work with NHibernate's one-to-one mapping. Note that the model you propose is identical to how a one-to-many relationship would be modeled.
It's legit and enforces the one-to-one relationship.
Since you want the recipe to always have an associated metadata row, I would model it using NHibernate's one-to-one mapping. Alternatively, you can map it as one-to-many but only expose one instance as a property.
See also: Ayende's post on the topic.
The following are two partial tables in which I am trying to define a foreign key relationship.
public class Form
{
[Key, Column("FormID")]
public System.Guid FormGUID { get; set; }
[Column("PatGUID")]
public Nullable<System.Guid> PatientGUID { get; set; }
}
public class Patient
{
[Column("PatGUID")]
public System.Guid PatientGUID { get; set; }
[Key, Column("PatID")]
public int PatientID { get; set; }
}
I've eliminated all but the relevant information, fields, navigations, etc. for this example; hopefully not too much.
We have a table Form, with a FK of PatGUID to a Patient table with field PatGUID.
The Patient table has a PatID int KEY field.
We have requirements to rename our fields for our code first entity models; the relevant fields in this example needing changed is PatGUID being changed to PatientGUID.
The difficulty I am having is trying to define this foreign key using either annotations or fluent.
So the end result I need is:
Primary Key Table: Patient, Field: PatGUID (renamed PatientGUID)
Foreign Key Table: Form, Field: PatGUID (renamed PatientGUID)
This doesn’t seem like it should pose a large problem but with the combination of Patient.PatGUID not being the primary key and the PatGUID fields being renamed to PatientGUID has not enabled the WCF Data Service to properly create a reference with a proper reference thus a proper select/join of:
SELECT … FROM [dbo].[Form] AS [Extent1]
INNER JOIN [dbo].[Patient] AS [Extent2] ON [Extent1].[PatGUID] = [Extent2].[PatGUID]
EF doesn't yet support relationships where the principal's key is not the primary key but some other column with a unique key constraint. It is on the feature request list but neither implemented nor on the road map for the next release (EF 6). If it gets implemented at all (in EF 7 maybe) expect to wait a year or more until it's ready for production.
In your particular model EF doesn't recognize any relationship between Form and Patient at all because Patient.PatientID is marked as [Key], not Patient.PatientGUID, and EF treats Form.PatientGUID as an ordinary scalar property, not as an FK to Patient.
In theory you could fake Patient.PatientGUID as the [Key] property in the model although it is not the primary key in the database if you don't create the model from the database or the database from a code-first model, that is, if you map between model and (existing) database manually. But I am not sure if this wouldn't cause subtle problems anywhere else.
The alternative is to write manual join statements in LINQ if you want to fetch Patients and related Forms. You can then join two entities using arbitrary properties, not only key properties. This is, in my opinion, the cleaner and less "tricky" approach. However, the downside is that you won't have navigation properties - references or collections - between Patient and Form and you can't use features like eager loading (Include), lazy loading or comfortable "dotted path syntax" (like Form.Patient.SomePatientProperty, etc.) in your LINQ queries.
I need to add a navigation property between two Entities TableA and TableB
TableA
ID : Primary Key
Code: String (Allows Null)
TableB
BID: Primary Key
Code: String (Allows Null)
Now I want to add a navigation property to these Entities which are related by the code which is not a foreign key. Can anyone tell me how this is possible
It is not possible because code is not PK in any of your tables. Navigation properties follows same rules as database relations - in principal table you must use PK and in dependent you specify FK. Databases also offers selecting unique key in principal table but EF doesn't support unique keys yet.
I get this error when writing to the database:
A dependent property in a ReferentialConstraint is mapped to a
store-generated column. Column: 'PaymentId'.
public bool PayForItem(int terminalId, double paymentAmount,
eNums.MasterCategoryEnum mastercategoryEnum, int CategoryId, int CategoryItemId)
{
using (var dbEntities = new DatabaseAccess.Schema.EntityModel())
{
int pinnumber = 0;
long pinid = 1; //getPinId(terminalId,ref pinnumber) ;
var payment = new DatabaseAccess.Schema.Payment();
payment.CategoryId = CategoryId;
payment.ItemCategoryId = CategoryItemId;
payment.PaymentAmount = (decimal)paymentAmount;
payment.TerminalId = terminalId;
payment.PinId = pinid;
payment.HSBCResponseCode = "";
payment.DateActivated = DateTime.Now;
payment.PaymentString = "Payment";
payment.PromotionalOfferId = 1;
payment.PaymentStatusId = (int)eNums.PaymentStatus.Paid;
//payment.PaymentId = 1;
dbEntities.AddToPayments(payment);
dbEntities.SaveChanges();
}
return true;
}
The schema is:
Is it possible that you defined a bad column relation between your tables?
In my case, I had different columns and one was set as autonumeric.
This error says that you are using unsupported relation or you have error in your mapping. Your code is most probably absolutely unrelated to the error.
The error means that you have some relation between entities where foreign key property in dependent entity is defined as store generated. Store generated properties are filled in the database. EF doesn't support store generated properties as foreign keys (as well as computed properties in primary keys).
I had the same problem. Based on the answers provided here I was able to track it and solve it, but I had a strange issue described below - it might help somebody in the future.
On my dependent tables, the foreign Key columns have been set to StoreGeneratedPattern="Identity". I had to change it to "None". Unfortunately, doing so inside designer didn't work at all.
I looked in the designer-generated XML (SSDL) and these properties were still there so I removed them manually. I also had to fix the columns on the database (remove the Identity(1,1) from CREATE TABLE SQL)
After that, the problem went away.
I had the same problem and after some digging in table design in sql server , I found that mistakenly i set table's primary key also as foreign key.
In this image you can see that JobID is table's primary key but also mistakenly foreign key.
My problem was caused by redundant defining of the Primary key in the configuration.
this
.Property(p => p.Id)
.HasColumnName(#"id")
.IsRequired()
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) // this is redundant when you want to configure a One-to-Zero-or-One relationship
.HasColumnType("int");
Remove this line
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
Example http://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx
This is enough to define the relationship
// Configure Student & StudentAddress entity
modelBuilder.Entity<Student>()
.HasOptional(s => s.Address) // Mark Address property optional in Student entity
.WithRequired(ad => ad.Student); // mark Student property as required in StudentAddress entity. Cannot save StudentAddress without Student
Re-check the relationship between Payment and the other tables/entities. Including the ones that shouldn't contain PaymentId because that's where the problem is most likely hiding.
When creating foreign keys in SQL Server Management Studio, the primary key is defaulted, and this default is reverted when the parent table is changed, so be careful to change values in the correct order in the "Tables and Columns" window.
Also, after you've fixed the problematic relationship, there's a good chance that a simple "Refresh" on the model won't correctly remove the erronous relationship from the model and you'll get the same error even after the "fix", so do this yourself in the model before performing a refresh. (I found this out the hard way.)
If you have checked your relationships and are good there.
Delete the table in the edmx and then update from database. This will save you doing the update manually.
For me it was a wrongly placed foreign key in the table but even after altering the table to fix it, it was still not working. You need to update the EDMX files (and not enough to "refresh" the table from the model, you need to remove and add the table again in the model).
In addition to the accepted answer, if you are using EF Reverse POCO generator or some other tool that generates your POCO's, make sure you regenerate them!
In my case Id field wich FK just in Entity Framework the propierty "StoreGeneratedPattern" was set "Itentity" instead of "None"
In my case the problem was caused by having a two-way 1-1 relationship:
class Foo{
[Key]
Id
[ForeignKey]
BarId
...
}
class Bar{
[Key]
Id
[ForeignKey]
FooId
...
}
I had to simply remove one of the two foreign keys (not necessary anyway).
In my case it was simply that I did not have permissions set properly on the database. I had read only set and Entity framework was giving me a ReferentialConstraint error which threw me off. Added additional write permissions and all was well.
In my case, I had a Database Generated property, and a ForeignKey navigation property set up to reference a 1 to 1 related table.
This wasn't something I could remove, I needed to be able to both set the primary key of the entity to be Database Generated AND I needed to be able to reference the 1 to 1 table as a navigation property.
Not sure if this is the same for others, but this problem was only showing up when creating a new entity, reading or editing existing entities did not exhibit the issue, so I got around the issue by creating an inherited version of my Context and using the Fluent method to switch off the navigation property when creating.
So, my original entity looked like this:
public partial class MyEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid id{ get; set; }
// Navigation
[ForeignKey("id")]
public PathEntity Path { get; set; }
}
So I made a special inherited context that looked like this:
private class _navPropInhibitingContext : EF.ApplicationDBContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<MyEntity>()
.Ignore(e => e.Path);
}
}
and then changed the code that created the new entity to make user of the new context type
using (var specialContext = new _navPropInhibitingContext())
{
var dbModel = new MyEntity()
{
...
};
specialContext.MyEntity.Add(dbModel);
await specialContext.SaveChangesAsync();
}
Hope this helps somebody
I have the same issue.
Here is my case, if you are adding a new record and has a primary key but is not auto-incremented, this will trigger an error.
I thought first that it will automatically generate the key for me so I leave the Id as blank.
Example:
Customer cust = new Customer();
//cust.Id - I left it blank
db.Customer.Add(cust);
db.SaveChanges();
But upon quick investigation, I forgot to set it's Identity to true and that would trigger an error once you do SaveChanges on your DbContext.
So make sure if your Identity is true or not.
In my case I was passing auto generated primary key of the same table in foreign key column so entity frame work is throwing an error that it can not set a value of that column which is not generated yet as we can only get autogenerated value after save change
Here BonusRequestId is my primary key which I was doing a mistake
I need to recreate a database with exactly the same values it has been originally created. So I need to add records with a pre-defined PK value. In this case, the PK is Identity in the database and when I try to define it's value, it is simply ignored, getting its value from the identity. No error is raised but the PK value that I supply is ignored.
example:
Category category = new Category()
{
CategoryID=1,
CategoryName="Beverages",
Description="Soft drinks, coffees, teas, beers, and ales"
};
ctx.Categories.Add(category);
ctx.SaveChanges();
Notes:
I'm using POCO, code first, so, I don´t have an EDMX Model to configure.
I don´t want to use ctx.Database.ExecuteSqlCommand(). I wish to maintain an Database agnostic approach.
In this case, the PK is Identity
In such case you should never manually insert its value. Once you set column as identity DB should be responsible for controlling the Id. Because of that there is no way to pass the value from EF (unless you want to break other functionality). You must use ExecuteSqlCommand and create complex SQL which will:
Turn on identity insert for the table
Insert record
Turn off identity insert for the table
Inserting value into identity column must be allowed by SET IDENTITY_INSERT tableName ON
I don't know if you scenario will let you do this, but if you define a composite key like as follows:
modelBuilder.Entity<Category>().HasKey(s => new { s.CategoryID, s.Name });
(using HasKey while running the DbContext.OnModelCreating method and EF 4.1 Code First), then you actually can control which values get inserted when you save the POCO object to the database.
I will say that, however, I would agree with Ladislav insofar as that the primary key values you are trying to maintain here are conceptually really more like data than record identifiers, and should be treated as such. Meaning, treat them as just data fields, and create a new primary key field on your POCO class in order to uniquely identify database records. e.g. for Category
public Int32 PK {get; set;}
and be sure to indicate it's intended to be the PK field from OnModelCreating
modelBuilder.Entity<Category>().HasKey(c => c.PK)