Hi im using AspNetCore with entity framework. I need a way to perform a non unique one to one relationship between two tables.
I have a person
public class Person {
public int PersonId {get;set;}
public int? LocationId {get;set;}
public string Name {get;set}
}
public class Location {
public int LocationId {get;set;}
public string Name {get;set}
}
I want to reuse the LocationId within the person table but im getting the following error
SqlException: Cannot insert duplicate key row in object 'dbo.Person' with unique index 'IX_Persons_LocationId'. The duplicate key value is (3).
The statement has been terminated.
I considered using a map table between them but the LocationId will still appear multiple times.
I've looked at defining a builder within OnModelCreating, but i cant find a IsUnique() extension method relating to a foreign key just the primary key
UPDATE
The above model works fine for the first person that i create, but fails when i try and create a second person with the same location as the first person.
The error is saying i can only use a location once within the LocationId field in the person table
Related
I've got an issue with EF Core in which I loop through a list of objects and create related elements in another list. As I process the first object everything is great, it is added to the list properly and looks great when we pull the information from the database.
At the start of the code for processing each object, I grab more detailed information from the database about that object (it's related objects and such). When the query executes for the second object information in another object changes. It changes a foreign key to be null for the first object instead of the proper value. If I look in the database as that occurs, the foreign key is set properly. This change in the foreign key shown in the query causes it to show as dirty in the context.
Therefore, when we finish processing the second object and make an update to the database, the system commits the (now) null foreign key to the database. This causes all sorts of issues, as you would expect.
partial object definition below
public partial class CommandType
{
public int? FkATSId { get; set; }
public virtual ATST FkATS { get; set; }
}
public partial class ATST
{
public virtual ICollection<FAT> FAT{ get; set; }
}
public partial class FAT
{
public int? FkDTRTId{ get; set; }
public virtual DTRT FkDTRT { get; set; }
}
public partial class DTRT
{
public int? FkFDTid{ get; set; }
public virtual FDT FkFDT{ get; set; }
}
public partial class FDT
{
...
}
The value that gets comes back as a change to null is FkFDTid in the DTRT.
if we are processing 5 of the items, 4 will end up with a null id and the last one will have the proper foreign key. If we processed 10, 9 would have the bad id and the last one would be good.
If I go through the code in the debugger and keep an eye on the context directly, the value does not come back from the query as null and so things work fine. But, only if I keep the context open in the locals tab of VS.
Does anyone have any ideas?
It turns out the issue was a discrepancy between the database and the entity framework context. The database for one of the items had the foreign key as not unique, but the context, for some reason, had it as unique.
We were able to store values into the database but if we queried the database and brought more than one record that had the same foreign key value, EF would think to itself: This can't be, that foreign key must be unique. I'll set the first one I grabbed to be null. Voila, they're not unique. Oh, because I changed that foreign key, the record is now dirty and will be committed to the database when we do a save changes.
The takeaway from this: if you see values that are different from what is stored in the database after you query the database, check foreign key and uniqueness constraints.
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)
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;}
I am working on an intranet app. My data context class has some references to table(s) in other databases.
For example, one of my classes is like this:
public class SomeClass
{
public int Id {get;set;}
public string Name {get;set;}
...
public int EnteredById {get;set;}
}
Here is EnteredById is in fact a foreign key to Employee table in another database (on the same server) and that table is not part of the Data Context class.
I know I cannot create a foreign key on this property and this is fine as long as I can keep it in this class/ table and provide a value for it by going to Employee table in another database and retrieving it from there based on User’s Windows User Name.
How do I handle this situation while Employee table is not part of my Data Context?
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.