key by navigation property using annotation (entity framework) - entity-framework

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;}

Related

Entity Framework - Database generated identity is not populated after save if it is not the key of the entity

I have a model like
public class MyEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Required]
public int Id { get; set; } // Id
[Required]
[Key]
public System.Guid GUID { get; set; }
}
The GUID property is the PK by design, but I have a db generated Id property that I use within my code to determine if the object is a new object that hasn't been saved yet.
When I save this object with Entity Framework, the Id property does not get back populated as normally happens for database generated properties (although usually these are keys). I have to query the DB for the object and grab the ID manually. It seems EF only back populates Key properties on SaveChanges.
Is there any way to get EF to automatically populate the Id property here? Setting it as the Key is not an option, I have dozens of tables that are FK'd to the GUID property and for good reason.
EDIT: I have discovered that the package https://entityframework-extensions.net/ is handling my save changes. If I use the standard EF savechanges it works, but not with the extensions version.
Disclaimer: I'm the owner of Entity Framework Extensions
It was indeed an issue in our library. This scenario was not yet supported for EF6.
However, starting from the v4.0.50, it should now work as expected.

Why is Entity Framework looking for the wrong foreign key column?

I've seen various questions on related topics, which seem like they would address my issue, but nothing I try seems to help.
I have an EF (6.1.3) model of an existing DB, which has been working fine. I've just added an additional column to a table, which represents a new relationship. Perhaps relevantly, the relationship is the second one between the two tables - the original Location is now joined by ActualDirectSite, both of them relating the Uniform and Location tables.
The moment I added the two new properties, ActualDirectSiteID and ActualDirectSite, my SELECT queries started failing with the error "Invalid column name 'Location_ID'". It's true that that column doesn't exist, but I don't see why EF is looking for it - it was happy before, but something has made it think the column name should be different. The failing name makes me think it's the original Location which is somehow no longer working.
Here's the Entity in question:
public partial class Uniform
{
public int ID { get; set; }
[Column("LocationID")]
public int? LocationID { get; set; }
[ForeignKey("LocationID")]
public virtual Location Location { get; set; }
public int? ActualDirectSiteID { get; set; }
[ForeignKey("ActualDirectSiteID")]
public virtual Location ActualDirectSite { get; set; }
}
And my (shortened) table def:
CREATE TABLE [dbo].[Uniforms](
[ID] [int] IDENTITY(1,1) NOT NULL,
[LocationID] [int] NULL,
[ActualDirectSiteID] [int] NULL)
The obvious solution to relying on convention causing incorrect assumptions about column names is to specify them explicitly, and so I've tried using Column annotations, and also to make sure that the ID and navigation properties know about each other using ForeignKey, but no dice. Any ideas?
EDIT: added missing LocationID field (already present in full code)
EDIT2: to be clear, before I added ActualDirectSiteID to the Entity it all worked fine, with no annotations required. I've just had another look at the generated SQL, and it seems like the Location_ID reference corresponds to the ActualDirectSite property:
//[Extent1] is "Uniform"
... , [Extent1].[LocationID] AS [LocationID], [Extent1].[ActualDirectSiteID] AS [ActualDirectSiteID], [Extent1].[Location_ID] AS [Location_ID], //...[Extent4] begins
EDIT3: I didn't include any of my Location entity, here it is:
[Table("Location")]
public partial class Location
{
public int ID { get; set; }
public virtual ICollection<Uniform> Uniforms { get; set; }
}
As noted in the comments: with multiple navigation properties to the same table, EF will get confused as to which navigation property refers to which inverse navigation property and ignore the FK mapping of those. A similar issue I stumbled across some time ago can be found in this SO question.
There are only two ways (I know of) to fix this issue:
Ignore at least all but one of the navigation properties with [NotMapped] or .Ignore() or
Add a inverse navigation property to (at least) all but one navigation properties to this table and adjust the mapping accordingly.
Actually, this behavior smells like a bug on EF side (from a DB point of view, I don't see the problem there), but the workaround is simple enough.
By convention every foreign key declaration include 2 properties.
If you create link to Location entity, then you must add property with name - LocationId type int. That is why you got an error
ForeignKey annotation is used to specify the name of used int id property for link (if you plan to use different name)
You can declare foreign key only like here:
public Location Location {get; set;}
public int LocationId {get; set;}
Or like here:
[ForeignKey("CustomIdProperty")]
public Location Location {get; set;}
public int CustomIdProperty {get; set;}
(Pardon me for possible typos - writting from phone)

One to One Relationship between primary key and unique key in EF6

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.

EF Code First One-To-One with Join Table

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.

EF code-first foreign key

I have a class Question
CompareItems store CurrentQuestion-to-OtherQuestion compare information.
public class Question
{
public virtual ICollection<QuestionMark> CompareItems { get; set; }
}
public class QuestionMark
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int Question { get; set; } //Store ID of OtherQuestion
public decimal Mark { get; set; }
}
When I delete some question A I need that all QuestionMark where QuestionMark.Question == A.Id also deleted, because it's no need to have compare information if question not exist. How it possible to do that without making QuestionMark.Question an entity? Maybe EF have some rule in Fluent-API to set that QuestionMark.Question is foreign key on Question entity?
I don't wont to make QuestionMark.Question as entity because it will need to change current solution lot - is a first. Also, question is a quite heavy entity, and to load it multiple time to assign value or delete or something else will be press on performance
I think it's possible to change app to use Entities instead of id, because EF use lazy loading by default and it will not caused performance problems. And I think that using just id instead of entity possible with some fluent API settings or attribute.
If you do not want to make a navigational property Question in QuestionMark class then you need to manually create a foreign key with "cascade delete". Then when every a question is deleted the database will delete the related QuestionMark records.
However this approach has a problem with EF. Because EF does not know there is a "cascade delete" relationship among these entities. So there can be inconsistencies within the locally tracked entities in EF.
You have not given a reason as to why you do not want to map the relationship in EF but I highly advice you against it.