Multiple zero or one to one relationships EF 6 Code First - c#

I have a contact table
public class Contact : EntityBase
{
public int TrivialContactProperty { get; set; }
...
public virtual FiContact FiContact { get; set; }
public virtual PuContact PuContact { get; set; }
public virtual TrContact TrContact { get; set; }
}
and then a FiContact, PuContact, and TrContact table.
public class FiContact : EntityBase
{
public int TrivialFiProperty { get; set; }
...
public virtual Contact Contact { get; set; }
}
public class PuContact : EntityBase
{
public int TrivialPuProperty { get; set; }
...
public virtual Contact Contact { get; set; }
}
public class TrContact : EntityBase
{
public int TrivialTRProperty { get; set; }
...
public virtual Contact Contact { get; set; }
}
The contact table should have a zero or one relationship with all three other tables. So a contact can exist without any of the other three, or it can be related to one or two or all three of them.
Using fluent API I tried to configure this, after doing some research, and I came up with:
modelBuilder.Entity<FiContact>()
.HasRequired(r => r.Contact)
.WithOptional(o => o.FiContact);
modelBuilder.Entity<PuContact>()
.HasRequired(r => r.Contact)
.WithOptional(o => o.PuContact);
modelBuilder.Entity<TrContact>()
.HasRequired(r => r.Contact)
.WithOptional(o => o.TrContact);
But I am still getting the following error when I try to add a migration for this change:
FiContact_Contact_Source: : Multiplicity is not valid in Role 'FiContact_Contact_Source' in relationship 'FiContact_Contact'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '(asterisk symbol here)'.
PuContact_Contact_Source: : Multiplicity is not valid in Role 'PuContact_Contact_Source' in relationship 'PuContact_Contact'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '(asterisk symbol here)'.
TrContact_Contact_Source: : Multiplicity is not valid in Role 'TrContact_Contact_Source' in relationship 'TrContact_Contact'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '(asterisk symbol here)'.
From more research I saw that the primary key on the dependent entity is supposed to also be the foreign key? The only problem is that all of my entities inherit from a class "EntityBase" which defines common fields in all entities, including the primary key:
public abstract class EntityBase : IEntity
{
[Key]
public int Id { get; set;}
public bool IsActive { get; set; }
public DateTime CreatedOnDate { get; set; }
public int? CreatedByUserId { get; set; }
[ForeignKey("CreatedByUserId")]
public User CreatedByUser { get; set; }
public DateTime LastUpdatedOnDate { get; set; }
public int? LastUpdatedByUserId { get; set; }
[ForeignKey("LastUpdatedByUserId")]
public User LastUpdatedByUser { get; set; }
}
Is there a way to make this kind of table/entity relationship work with EF 6 Code First? Any help getting this type of relationship to work would be much appreciated.

Related

EntityFramework 1 to 0, 1 or many relationship

I am struggling to create a relationship in Entity framework between three tables..
I am developing WPF application using C#, Sqlite 3.0 and Entity Framework 6.
I have Following tables(classes):
Investor
Investment
ImageStore
I want to create a model so that Investor and Investment (and future other classes) can store either 0, 1 or Many images.. (as it is obvious from class names that Investor can have only one profile image and Investment class can have multiple images)
My ImageStore class looks something like this:
public class ImageStore : PropertyChangedNotification
{
[Key]
public int ImageStoreId { get; set; }
[Required]
public string ImageFile { get; set; }
[Required]
public Byte[] ImageBlob { get; set; }
public string FileName { get; set; }
[Required]
public int FileSize { get; set; }
//public virtual ImageData ImageData { get; set; }
}
In order to create 1 to 0,1 or Many relationship, I created one more intermediate table called: ImageData as seen below (I don't know whether it is really a good approach but that is only what I can think of right now..)
public class ImageData : PropertyChangedNotification
{
[Key]
public int ImageDataId { get; set; }
[ForeignKey("Investment")]
public long? InvestmentId { get; set; }
[ForeignKey("Investor")]
public long? InvestorId { get; set; }
[ForeignKey("ImageStore")]
public int ImageStoreId { get; set; }
public virtual ImageStore ImageStore { get; set; }
public virtual Investment Investment { get; set; }
public virtual Investor Investor { get; set; }
}
My Investor class looks like this:
public class Investor : PropertyChangedNotification
{
[Key]
public long InvestorId { get; set; }
[NotMapped]
[ForeignKey("ImageData")]
public List<int> ImageDataList { get; set; }
public virtual ICollection<ImageData> ImageDataCollection { get; set; }
public virtual ICollection<Investment> Investments { get; set; }
}
My Investment Class Looks like this:
public class Investment : PropertyChangedNotification
{
[Key]
public long InvestmentId { get; set; }
[ForeignKey("Investor")]
[Required]
public long FirstInvestorId { get; set; }
[NotMapped]
[ForeignKey("ImageData")]
public List<int> ImageDataList { get; set; }
public virtual ICollection<ImageData> ImageDataCollection { get; set; }
public virtual Investor Investor { get; set; }
[NotMapped]
[Required (ErrorMessage = "First Investor is Required")]
public Investor FirstInvestor { get; set; }
}
This is my related fluent configuration:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// MyData Database does not pluralize table names
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Investor>().HasOptional(s => s.ImageDataCollection);
modelBuilder.Entity<Investment>().HasOptional(s => s.ImageDataCollection);
//modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
}
When I start debugging the application, I get the following error:
ImageData_Investment_Source: : Multiplicity is not valid in Role 'ImageData_Investment_Source' in relationship 'ImageData_Investment'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'
ImageData_Investor_Source: : Multiplicity is not valid in Role 'ImageData_Investor_Source' in relationship 'ImageData_Investor'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'
Can someone please suggest me either a solution to this problem and/or optimal approach to achieve what I need, I really will appreciate.
Thanks
The fluent configuration
modelBuilder.Entity<Investor>().HasOptional(s => s.ImageDataCollection);
modelBuilder.Entity<Investment>().HasOptional(s => s.ImageDataCollection);
is incomplete.
Since the you already have the necessary data annotations and navigation / FK properties, you can simply remove it. Or if you want to provide fluent configuration (which I personally prefer because it allows you to specify everything explicitly and not rely on conventions and specifically for relationships, not so intuitive ForegnKey and InverseProperty data annotations), then you should make sure it reflects exactly the presense/absence of the navigation and FK properties in the involved entities.
The correct fluent configuration reflecting your model so far is like this:
modelBuilder.Entity<Investor>()
.HasMany(e => e.ImageDataCollection)
.WithOptional(e => e.Investor)
.HasForeignKey(e => e.InvestorId);
modelBuilder.Entity<Investment>()
.HasMany(e => e.ImageDataCollection)
.WithOptional(e => e.Investment)
.HasForeignKey(e => e.InvestmentId);

One to one relationship with nullable foreign key in Entity Framework

I'm trying to create database relationship between two tables.
I have redemption codes which can be free. But one user has only one redem code.
I created two entities:
public class UserProfile
{
[Key]
[ForeignKey("User")]
public int Id { get; set; }
//... other fields
public virtual RedemptionCode RedemptionCode { get; set; }
public virtual User User { get; set; }
}
public class RedemptionCode
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[ForeignKey("UserProfile")]
public int? UserProfileId { get; set; }
public virtual UserProfile UserProfile { get; set; }
[Required]
public string Code { get; set; }
}
But when I adding a migration I have the following error:
One or more validation errors were detected during model generation:
RedemptionCode_UserProfile_Source: : Multiplicity is not valid in Role 'RedemptionCode_UserProfile_Source' in relationship 'RedemptionCode_UserProfile'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
What do I really want? I want to store free redem codes in db and link one of them with new user in my system.
Here is the right code for the UserProfile class
public class RedemptionCode
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key,ForeignKey("UserProfile")]
public int Id { get; set; }
public int? UserProfileId { get; set; }
[ForeignKey("UserProfile")]
public virtual UserProfile UserProfile { get; set; }
[Required]
public string Code { get; set; }
}
You have to move the ForeignKey from the property UserProfileId to the navigation property UserProfile and indicate that UserProfile is the principal in the relationship by adding the ForeignKey attribute to the Id of the RedemptionCode class

EF Code first 1 to 1 relationship error

I have two classes:
Main class:
public class CCourseDetailModel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CourseDetailId { get; set; }
[ForeignKey("CourseOutcomes")]
public int CourseOutcomesId { get; set; }
public virtual CACourseOutcomesModel CourseOutcomes { get; set; }
}
Dependent class:
public class CACourseOutcomesModel
{
[Key, ForeignKey("CourseDetail")]
public int CourseOutcomesId { get; set; }
[Required]
public virtual CCourseDetailModel CourseDetail { get; set; }
}
I have 10 or so similar classes, with 1 to 1 relationships that work fine. This is the only one giving me the following error:
CACourseOutcomesModel_CourseDetail_Target: : Multiplicity is not valid in Role 'CACourseOutcomesModel_CourseDetail_Target' in
relationship 'CACourseOutcomesModel_CourseDetail'. Because the
Dependent Role properties are not the key properties, the upper bound
of the multiplicity of the Dependent Role must be ''.*
Any idea where I'm going wrong? Need a fresh set of eyes please. Thanks!
In a one to one relationship, one end must be principal and the another one must be dependent, so you can't have a FK property in both sides. Remove the FK property in the principal (CCourseDetailModel) and in CACourseOutcomesModel you don't need to use Required attribute. Using ForeignKey attribute you already are telling to EF who is the dependent end.
In Fluent Api would be:
modelBuilder.Entity<CACourseOutcomesModel>()
.HasRequired(p => p.CourseDetail)
.WithOptional(p => p.CourseOutcomes);
So your model should be this way:
public class CCourseDetailModel
{
[Key]
//[DatabaseGenerated(DatabaseGeneratedOption.Identity)] don't need this, it's the configuration by default.
public int CourseDetailId { get; set; }
public virtual CACourseOutcomesModel CourseOutcomes { get; set; }
}
public class CACourseOutcomesModel
{
[Key, ForeignKey("CourseDetail")]
public int CourseOutcomesId { get; set; }
public virtual CCourseDetailModel CourseDetail { get; set; }
}

EF Code First 1:0..1 relationship error: Multiplicity is not valid in Role 'EFEmployee_Identity_Source' in relationship 'EFEmployee_Identity'

Full error:
One or more validation errors were detected during model generation:
EFEmployee_Identity_Source: : Multiplicity is not valid in Role 'EFEmployee_Identity_Source' in relationship 'EFEmployee_Identity'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
I am dealing with three types of entities: EFEmployee, EFPerson, and EFOffice. It's kind of weird that I'm getting this error because the code I'm testing only creates an instance of an EFOffice entity. Anyway, here is the EFEmployee entity class:
[Table("employee_entity")]
public class EFEmployee : EFBusinessEntity
{
[ForeignKey("Office")]
public Guid OfficeID { get; set; }
[ForeignKey("Identity")]
public Guid PersonID { get; set; }
[Column("hire_date")]
public DateTime HireDate { get; set; }
[Column("job_title")]
public byte[] JobTitle { get; set; }
[Column("salary")]
public int Salary { get; set; }
[Column("certifications")]
public byte[] Certifications { get; set; }
[Column("vacation_time")]
public int VacationTime { get; set; }
[Column("sick_time")]
public int SickTime { get; set; }
public virtual EFOffice Office { get; set; }
public EFPerson Identity { get; set; }
public virtual EFEmployee ReportingTo { get; set; }
}
And this is my EFPerson entity class:
[Table("person_entity")]
public class EFPerson : EFBusinessEntity
{
[Column("first_name")]
[StringLength(50)]
public string FirstName { get; set; }
[Column("last_name")]
[StringLength(50)]
public string LastName { get; set; }
[Column("phone_num")]
public uint? PhoneNum { get; set; }
[Column("date_of_birth")]
public DateTime DateOfBirth { get; set; }
public EFEmployee Employee { get; set; }
}
You can see that they both inherit from EFBusinessEntity, which is here:
[Table("business_entity")]
public abstract class EFBusinessEntity : IBusinessEntity
{
[Column("tenant_id")]
public Guid TenantId
{
get;
set;
}
[Column("id")]
[Key]
public Guid Id
{
get;
set;
}
}
As you can see, there is a one-to-zero-or-one relationship between EFEmployee and EFPerson, with EFEmployee being the dependent side since there can be a person who is not an employee, but there can't be an employee who is not a person too. Since EFEmployee is the dependent side, I have added a PersonID in EFEmployee with the data annotation (attribute?) above denoting that it's the foreign key to Person:
[ForeignKey("Identity")]
public Guid PersonID { get; set; }
I think I've made it pretty clear for Entity Framework that this is a 1:0..1 relationship. Does anyone know how to solve this error using data annotations (or attributes, whatever those square bracket things above properties are). I can't use fluent API for reasons I'm not getting into.
Generally, with 1:0..1 relationships in Entity Framework, the dependent side needs to use its primary key as the foreign key. Fortunately, for your case, this doesn't seem like it would be a bad idea. You would need to:
Remove the EFEmployee.PersonID property
Add [ForeignKey("Id")] to EFEmployee.Identity
Edit: May not work because key and navigation property are on separate classes. See this.
Having EFEmployee inherit from EFPerson seems like it might be a viable option as well. Inheritance uses TPH by default, but if you want to use TPT (table-per-type), add the [Table] attribute to your type.
I did some more playing around with the models and found out what was wrong. So I kept the foreign key attribute with EFPerson.Identity like jjj suggested:
[ForeignKey("PersonID")]
public virtual EFPerson Identity { get; set; }
Then the other change I had to make was in the EFPerson class. In my EFPerson class I had the navigation property to EFEmployee:
public virtual EFEmployee Employee { get; set; }
However, since this is a 1:0..1 relationship with EFEmployee being the dependent side (i.e. the non-essential side), I removed that navigation property, and when I ran my test it worked.

Entity Framework - Multiple tables referencing to one table

I came here with an Entity Framework problem which I'm struggling with for some time already. Let's describe it quickly. I have 2 models that are referencing to one model... and I don't really know how can I create the relationship with EF annotations.
First model:
public class ProcessedLog
{
[Key]
public int Id { get; set; }
// Some other data
public virtual LogLocation Location { get; set; }
}
Second model:
public class QueuedLog
{
[Key]
public int Id { get; set; }
// Some other data
public virtual LogLocation Location { get; set; }
}
And the model that I'm referencing to:
public class LogLocation
{
[Key]
public int Id { get; set; }
[ForeignKey("QueuedLog")]
public int QueuedLogId { get; set; }
[ForeignKey("ProcessedLog")]
public int ProcessedLogId { get; set; }
// Some other data
public virtual QueuedLog QueuedLog { get; set; }
public virtual ProcessedLog ProcessedLog { get; set; }
}
As you can see, I've already tried to do something but it's not working properly. I'm getting an error:
LogLocation_ProcessedLog_Source: : Multiplicity is not valid in Role 'LogLocation_ProcessedLog_Source' in relationship 'LogLocation_ProcessedLog'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be ''.
LogLocation_QueuedLog_Source: : Multiplicity is not valid in Role 'LogLocation_QueuedLog_Source' in relationship 'LogLocation_QueuedLog'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be ''.
It works only when I do typical one-to-one relationship - but this is not what i want.
Btw. this is my first post at StackOverflow so i would like to say hi to everyone! :) You're creating a great community, thanks for all your work!
Edit
The question is: how can i create these models and relationshiph so it would work like this:
I add new ProcessedLog to Db -> It adds a new LogLocation with ProcessedLogId equal to the related ProcessedLog and the QueuedLogId is NULL.
You can do it like this. Database wise I am not sure if this is a great solution... Though it does look like it will work for you.
It worked with EntityFramework 6.1.3 and SQL Server Express.
ProcessedLog.cs
public class ProcessedLog
{
[Key]
public int Id { get; set; }
// Some other data
public virtual LogLocation Location { get; set; }
}
QueuedLog.cs
public class QueuedLog
{
[Key]
public int Id { get; set; }
// Some other data
public virtual LogLocation Location { get; set; }
}
LogLocation.cs
public class LogLocation
{
[Key]
public int Id { get; set; }
// Some other data
public virtual QueuedLog QueuedLog { get; set; }
public virtual ProcessedLog ProcessedLog { get; set; }
}
Context.cs
public class Context : DbContext
{
public DbSet<ProcessedLog> ProcessedLogs { get; set; }
public DbSet<QueuedLog> QueuedLogs { get; set; }
public DbSet<LogLocation> LogLocations { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ProcessedLog>()
.HasRequired(p => p.Location)
.WithOptional(l => l.ProcessedLog);
modelBuilder.Entity<QueuedLog>()
.HasRequired(p => p.Location)
.WithOptional(l => l.QueuedLog);
}
}
Also the code I tested it with
using (var context = new Context())
{
var processedLog = new ProcessedLog
{
Location = new LogLocation()
};
var queuedLog = new QueuedLog
{
Location = new LogLocation()
};
context.ProcessedLogs.Add(processedLog);
context.QueuedLogs.Add(queuedLog);
context.SaveChanges();
}

Categories

Resources