Entity Framework one to zero one association reference key mapping [duplicate] - c#

I am trying to establish a One-to-Zero-or-One relationship between two entities and I want the dependent entity to still contain its own Indentity column, instead of it being a shared key.
I want to do as much as possible following the conventions and not declaring explicitly anything that does not require explicit declaration (so, no unnecessary data annotations or fluent api clauses)
The entites:
public class File
{
public int FileId {get;set;}
//some omitted file properties
public virtual Task Task {get;set;}
}
public class Task
{
public int TaskId {get;set;}
//some omitted task properties
public int FileId {get;set;}
public virtual File File {get;set;}
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<File>().HasOptional(f => f.Task).WithRequired(t => t.File);
base.OnModelCreating(modelBuilder);
}
This creates a weird relation where the TaskId is both PK and FK column of the Tasks table. Which, I think means that it should have the same value as the file ID? (That is a question:) )
So, how do I make TaskId hold its own, sequential value and have FileId become a foreign key to the Files table?
Or maybe in case of 1-0..1 I should rather get rid of the TaskId property and make FileId the PK/FK property?
Cheers!

Bidirectional one-to-one relationship with explicit FK property is not supported.
So either continue using what you have now - Shared Primary Key association. Just get rid of one of the TaskId or FileId properties from Task and make the remaining a PK (EF will automatically use it as FK because that's the default EF one-to-one relationship model).
Or get rid of the FieldId property from Task and use the following fluent configuration (all is necessary):
modelBuilder.Entity<File>()
.HasOptional(f => f.Task)
.WithRequired(t => t.File)
.Map(m => m.MapKey("FileId"))
.WillCascadeOnDelete();
But I would recommend using the first approach (if there is no special reason of not doing it like existing database etc.) because it's better supported - the second includes some LEFT OUTER JOINs in SQL queries as you can see from this post EF - WithOptional - Left Outer Join?.

Related

EF code first - configure One-to-Zero-or-One relationship without shared PK/FK

I am trying to establish a One-to-Zero-or-One relationship between two entities and I want the dependent entity to still contain its own Indentity column, instead of it being a shared key.
I want to do as much as possible following the conventions and not declaring explicitly anything that does not require explicit declaration (so, no unnecessary data annotations or fluent api clauses)
The entites:
public class File
{
public int FileId {get;set;}
//some omitted file properties
public virtual Task Task {get;set;}
}
public class Task
{
public int TaskId {get;set;}
//some omitted task properties
public int FileId {get;set;}
public virtual File File {get;set;}
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<File>().HasOptional(f => f.Task).WithRequired(t => t.File);
base.OnModelCreating(modelBuilder);
}
This creates a weird relation where the TaskId is both PK and FK column of the Tasks table. Which, I think means that it should have the same value as the file ID? (That is a question:) )
So, how do I make TaskId hold its own, sequential value and have FileId become a foreign key to the Files table?
Or maybe in case of 1-0..1 I should rather get rid of the TaskId property and make FileId the PK/FK property?
Cheers!
Bidirectional one-to-one relationship with explicit FK property is not supported.
So either continue using what you have now - Shared Primary Key association. Just get rid of one of the TaskId or FileId properties from Task and make the remaining a PK (EF will automatically use it as FK because that's the default EF one-to-one relationship model).
Or get rid of the FieldId property from Task and use the following fluent configuration (all is necessary):
modelBuilder.Entity<File>()
.HasOptional(f => f.Task)
.WithRequired(t => t.File)
.Map(m => m.MapKey("FileId"))
.WillCascadeOnDelete();
But I would recommend using the first approach (if there is no special reason of not doing it like existing database etc.) because it's better supported - the second includes some LEFT OUTER JOINs in SQL queries as you can see from this post EF - WithOptional - Left Outer Join?.

Saving OData entities from api with id to database in entity framework

I have multiple projects that return the same OData entities through a API endpoint. Now i want to call all of the projects and store them in my calling projects database with entity framework.
To add them to the db the ID gets overwritten but i want to save the id that the entity has in the projects database as well. so i can still access them if need be and to check if the data isn't already in my database. Because of this i need to add another MainProjectID and projectID column to the entity.
I tried making a new class that has a reference to the entity i want to save but this used new id's for the entities. I also tried inheriting the class but this gave me key conflict issues, and generics don't work either in entity framework(i'm not saying they should). So i'm kinda at a loss right now.
I basically want to save the id as a non-key. Is there any way i can do this without writing entirely new classes and parsing them manually ?
Any help would be greatly appreciated.
We have multiple alternatives here:
In a distributed system, best way to cope with these kinds of ID clashes is to make IDs globally unique. If you can modify how IDs are generated, that would be my choice to go. You can use a UUID (or Microsoft implementation GUID) that will produce a universal unique identifier. Or if that seems like an overkill you can devise a simple mechanism that combines ID with projectID. However you should ensure that the method you will use will not produce any collisions (no two different id-projectId pair will map to same value).
This will ensure that same entity is used throughout your application and no overlaps occur if you try to put records from different sources into the same table. You only need to implement a mechanism to record which ID originated from which source. You can use a reference entity at aggregator for this purpose. You also need to disable auto increment nature of the ID column so that your global unique values are used in table.
You can use different entities for producing and aggregating applications. I don't know your application, but that seems like an OK approach to me since the aggregating application has a different idea about the entity. The aggregating application cares for which application produced the entity, that might make putting the source application identifier into the entry justifiable. Your entities will only differ in that and when you receive the OData object from API you'll need copy all other properties and put project identifier yourself.
You can use the previous solution, but you can use a derived class in order to not to repeat your object properties. This is a better design alternative. However with this method you'll have some problems with the primary key (as you've stated you had). Consider this example
public class Base {
public int ID { get; set; }
[Required]
[StringLength(50)]
[Display(Name = "Name")]
public string Name { get; set; }
}
public class Derived : Base {
[Key]
public int projectId {get; set; }
}
If you don't put [Key] to Derived then you'll have only ID as primary key. When you put [Key] to Derived then you'll have only projectId as primary key. You need to define a composite key and you can do this by removing the [Key] annotation from projectId and using the onModelCreating override of DbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Derived>().HasKey(a => new { a.ID, a.projectId })
.Property(c => c.ID).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
modelBuilder.Entity<Derived>().Property(c => c.projectId).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
}
You can mix these alternatives. You can drop the primary key on ID field, and then you can insert a new Entity that will model 1-M relationship between ID's and project ID's.

Navigation property without referential integrity constraint in Entity Framework 6

In EF 6 (code first), is it possible to have a navigation property set-up without enforcing a referential integrity constraint?
For example:
public class Person{
public IList<Pet> Pets { get; set; }
}
public class Pet{
public int OwnerId { get; set; }
public Person Owner { get; set; }
}
So in the example above I'd like to be able to add a Pet with an OwnerId, even if that owner does not exist in the Owners table.
Thanks
Matt
You can define the relationship using the fluent API.
modelBuilder.Entity<Pet>
.hasOptional(p => p.Owner)
.willCascadeOnDelete(false);
This will configure the relational property as optional, and will ensure that cascade delete does not take effect. You can create a Pet without an Owner, and deleting an Owner will not delete the associated Pets.
However you cannot assign Pet.OwnerId to an OwnerId that doesn't exist in the Owner table. If you truly need to have some way of tracking invalid OwnerId values, you either need to have a separate property which you manually update with an arbitrary value, or you would need to define these objects without using a navigation property, and perform your lookups manually.
It would be an exceptional situation where you would need to supply an arbitrary value for OwnerId that doesn't match the Owner table; In 99% of all cases, an optional relationship which accepts a valid OwnerId or null is all that is necessary.
The OwnerId property isn't actually necessary on the Pet object, but if it is present, it should be set to int? to be nullable.
Short Answer: Don't use EF. The whole point of Object Relational Mappers is to ensure you have valid data as well as help with retrieving/persisting it
All you really want is some sort of mapper.
Long Answer: Curious myself

One to one relationship between 2 entities, both are inherited from the same abstract class

I have 2 Entities which inherit same abstract class.
How to organize one-to-one relationship between that Entities?
[Table("AbstractObjects")]
public abstract class AbstractObject{
public Guid Id{get;set;}
public string Name{get;set;}
public DateTime CreateDate{get;set;}
}
[Table("FolderObjects")]
public class Folder:AbstractObject{
public virtual Content Content{get;set;}
}
[Table("ContentObjects")]
public class Content:AbstractObject{
public virtual Folder Folder{get;set;}
}
Standard solution works improperly, it makes one-to-many relationship
modelBuilder.Entity<Folder>()
.HasRequired(x => x.Content)
.WithRequiredDependent(c => c.Folder);
Try the following:
modelBuilder.Entity<Folder>()
.HasRequired(x => x.Content)
.WithRequiredPrincipal(); // <- this is what's different
Edit:
The problem is your inheritance implementation - why don't you explain what you're trying to accomplish with your inheritance strategy - my guess is you want the folder/content tuple to contain the exact same data represented by the AbstractObjects entity, but in your implementation the Folder and Content entities will have their own distinct copy of the AbstractObjects data.
If that is the case, you have two options - define Folder and Content to live in the same table and use table splitting to define the Folder and Content entities. Your second option is to use shared primary keys between the entities.
If that is not the case, you want associated Folder and Content entities to have the possibility of having different AbstractObject values; you should remove the table annotation on the AbstractObject entity class definition so that their values are incorporated into the FolderObjects and ContentObjects tables.
After some seaches(googling), I get that I need unique constraint on FolderId field(explicitly created) of Content type, but EF is not supporting unique constraints for fields for now. Thus the relationship stay on one-to-many. Thanks to all participants!!!

Entity Framework Code First: Custom Mapping

public class User
{
public int Id {get;set;}
public string Name {get;set}
public ICollection<User> Followers {get;set;}
public ICollection<User> Following {get;set;}
}
My Model looks like above, Entity framework automatically creates A table and UserUser with rows User_ID and User_ID1 in DB to map this model. I want to map that table and rows myself.
How can i do that, Thanx!!
From Scott Gu's blog about Many-valued Associations:
Many-to-Many Associations
The association between Category and Item is a many-to-many
association, as can be seen in the above class diagram. a many-to-many
association mapping hides the intermediate association table from the
application, so you don’t end up with an unwanted entity in your
domain model. That said, In a real system, you may not have a
many-to-many association since my experience is that there is almost
always other information that must be attached to each link between
associated instances (such as the date and time when an item was added
to a category) and that the best way to represent this information is
via an intermediate association class (In EF, you can map the
association class as an entity and map two one-to-many associations
for either side.).
In a many-to-many relationship, the join table (or link table, as some
developers call it) has two columns: the foreign keys of the Category
and Item tables. The primary key is a composite of both columns. In EF
Code First, many-to-many associations mappings can be customized with
a fluent API code like this:
class ItemConfiguration : EntityTypeConfiguration<Item> {
internal ItemConfiguration()
{
this.HasMany(i => i.Categories)
.WithMany(c => c.Items)
.Map(mc =>
{
mc.MapLeftKey("ItemId");
mc.MapRightKey("CategoryId");
mc.ToTable("ItemCategory");
});
} }
Register this configuration in your DbContext's (you using the DbContext api right?) like this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new ItemConfiguration());
}
Good luck, hope this help!
To map an entity to itself, you would do something like this
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasMany(u => u.Followers)
.WithMany().ForeignKey(u => u.FollowerId);
base.OnModelCreating(modelBuilder);
}
its hard to tell without seeing your database model though, and how you actually relate the followers to the user.

Categories

Resources