Say I have three tables. Settings, Facilities and FacilitySettingOverride in an existing database. The sample data:
Settings table
ID Name Value
1 test1 true
2 test2 true
Facilities table
ID Name
163 Demo1
164 Demo2
FacilitySettingOverride
FacilityId SettingId Value
163 2 False
164 1 False
164 2 False
FacilitySettingOverride has two foreign keys---FacilityId and SettingId. Also I want to make a composite key for FacilitySettingOverride.
I just don't know how to make it. My primary code.
[Table("Settings")]
public class Setting
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public FacilitySettingOverride FacilitySettingOverride { get; set; }
}
[Table("Facilities")]
public class Facility
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<FacilitySettingOverride> FacilitySettingOverrides { get; set; }
}
[Table("FacilitySettingOverride")]
public class FacilitySettingOverride
{
[Key]
[ForeignKey("FacilityId")]
public int FacilityId { get; set; }
public string Value { get; set; }
[ForeignKey("SettingId")]
public int SettingId { get; set; }
public virtual Facility Facility { get; set; }
public virtual Setting Setting { get; set; }
I guess that it is wrong. Thanks for help.
Looking at your data and description, both Settings and Facility have one-to-many associations to FacilitySettingOverride. So Setting shouldn't have a property ...
public FacilitySettingOverride FacilitySettingOverride { get; set; }
... but a collection of FacilitySettingOverrides, just as Facility has.
This should be the proper class model:
[Table("Settings")]
public class Setting
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public virtual ICollection<FacilitySettingOverride> FacilitySettingOverrides { get; set; }
}
[Table("Facilities")]
public class Facility
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<FacilitySettingOverride> FacilitySettingOverrides { get; set; }
}
[Table("FacilitySettingOverride")]
public class FacilitySettingOverride
{
[Key, Column(Order = 1)]
[ForeignKey("Facility")]
public int FacilityId { get; set; }
[Key, Column(Order = 2)]
[ForeignKey("Setting")]
public int SettingId { get; set; }
public virtual Facility Facility { get; set; }
public virtual Setting Setting { get; set; }
public string Value { get; set; }
}
The combination of KeyAttribute and ColumnAttribute ([Key, Column(Order = 1)]) is used for composite primary keys.
This is the database schema EF creates from it:
Related
I have the following models
public class Company
{
[Key, Column(Order=0)]
public int Id {get;set;}
public string CompanyCode { get; set; }
public string Name { get; set; }
public virtual ICollection<Account> Accounts { get; set; }
public virtual ICollection<Journal> Journals { get; set; }
}
public class Account
{
[Key, Column(Order=0)]
public int Id { get; set; }
[Key, Column(Order=1), ForeignKey("Company")]
public int CompanyId { get; set; }
public int GLAccountNumber { get; set; }
public decimal Balance { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<Journal> Journals { get; set; }
}
public class Journal
{
[Key, Column(Order=0)]
public int Id { get; set; }
[Key, Column(Order=1), ForeignKey("Company")]
public int CompanyId { get; set; }
[ForeignKey("Account")]
public int AccountId { get; set; }
public DateTime EntryDate { get; set; }
public decimal Amount { get; set; }
public virtual Company Company { get; set; }
public virtual Account Account { get; set; }
}
How would I map the relationship between these models, Specifically I cannot figure out how to define the Composite Key in the Journal Model to map to Account By CompanyId, AccountId
You could use fluent APi (my personal preference - clear and less error prone):
modelBuilder.Entity<Journal>()
.HasRequired(e => e.Account)
.WithMany(e => e.Journals)
.HasForeignKey(e => new { e.AccountId, e.CompanyId });
But if you prefer data annotations, then apply the ForeignKey attribute on the navigation property and specify comma separated list of the FK properties:
public class Journal
{
[Key, Column(Order=0)]
public int Id { get; set; }
[Key, Column(Order=1)]
public int CompanyId { get; set; }
public int AccountId { get; set; }
public DateTime EntryDate { get; set; }
public decimal Amount { get; set; }
[ForeignKey("CompanyId")]
public virtual Company Company { get; set; }
[ForeignKey("AccountId,CompanyId")]
public virtual Account Account { get; set; }
}
My EF Code First model for some reason is not in sync with the db. I'm getting this error:
{"Invalid column name 'Type_Id1'."}
The field is actually called 'Type_Id' so I'm not sure from where that 1 comes up. I have the table column called as Type_Id and also I've added a Type_Id in my type entity model.
Why might I be getting that error message, plus why I'm getting 1 at the end of the name?
Update
My Task class:
public class Task
{
public Task()
{
Language = 1;
Grades = new HashSet<Grade>();
Categories = new HashSet<Category>();
Subjects = new HashSet<Subject>();
Rooms = new Collection<Room>();
Tools = new Collection<Tool>();
}
[Key]
public int Id { get; set; }
public string Description { get; set; }
public virtual TaskType Type { get; set; }
public string Rules { get; set; }
[Required]
[StringLength(200), MinLength(1)]
public string Name { get; set; }
public int PreperationTime { get; set; }
public int InstructionTime { get; set; }
public int TaskTime { get; set; }
public int Type_Id { get; set; }
public string VideoLink { get; set; }
[Required]
public int Language { get; set; }
public int? MinimumParticipants { get; set; }
public int? MaximumParticipants { get; set; }
public int? Rating { get; set; }
[Required]
public string CreatedBy { get; set; }
public virtual ICollection<Grade> Grades { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<Subject> Subjects { get; set; }
public virtual ICollection<Room> Rooms { get; set; }
public virtual ICollection<Tool> Tools { get; set; }
}
DBContext class:
public ApplicationDbContext() : base("DefaultConnection", false)
{
}
public DbSet<Task> Tasks { get; set; }
public DbSet<TaskType> TaskTypes { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
You need to add the FK attribute on your navigation property. EF is creating Type_Id1 because Type_Id already exists (although it can't tell by convention it is the FK).
[ForeignKey("Type_Id")]
public virtual TaskType Type { get; set; }
https://msdn.microsoft.com/en-us/data/jj591583.aspx#Relationships
I have two models in my application: Stock and Report. A report can have many stocks and a stock can be used in many reports.
public enum ElectionType
{
MANAGER =1 ,
INSPECTOR ,
BOTH
}
public class Report
{
public Report()
{
Stocks = new List<Stock>();
}
public int ReportID { get; set; }
[Required]
public DateTime ShamsiDate { get; set; }
public int? StockID { get; set; }
[Required]
public ElectionType ElectionType { get; set; }
[ForeignKey("StockID")]
public virtual ICollection<Stock> Stocks { get; set;}
}
public class Stock
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int StockID { get; set; }
public int FinancialCode { get; set; }
public String NationalCode { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
public String FatherName { get; set; }
public String Place { get; set; }
public int StockCount { get; set; }
public int StockPrice { get; set; }
public int StockSize { get; set; }
public int StartStock { get; set; }
public int EndStock { get; set; }
}
I want to create a one way relationship so there is no way to access a Report from a Stock. I have written this code but it doesn't work.
To do it with annotations you will need a junction table:
public class ReportStock
{
[Key, Column(Order = 1)]
public int ReportID { get; set; }
[Key, Column(Order = 2)]
public int StockID { get; set; }
[ForeignKey("ReportID")]
public virtual Report Report { get; set;}
[ForeignKey("StockID")]
public virtual Stock Stock { get; set;}
}
Then change your Report class:
public class Report
{
public Report()
{
ReportStocks = new List<ReportStock>();
}
public int ReportID { get; set; }
[Required]
public DateTime ShamsiDate { get; set; }
[Required]
public ElectionType ElectionType { get; set; }
public virtual ICollection<ReportStock> ReportStocks { get; set;}
}
I have nested object in EF Code First using Silverlight RIA service, I am able to get the data at service side but when I see it on client side child objects are null. Could you please guide me what's wrong.
[HasSelfValidation]
public class Batch
{
public int BatchId { get; set; }
public string BatchName { get; set; }
[Include]
[Composition]
[Association("FK_Batch_BathSetItemSet", "BatchId", "BatchSetIdItemSetId")]
public virtual ICollection<BatchSetItemSet> BatchSetItemSets { get; set; }
}
public class BatchSetItemSet
{
public int BatchSetIdItemSetId { get; set; }
public int BatchId { get; set; }
public Nullable<int> ItemSetId { get; set; }
public string CreatedBy { get; set; }
public Batch Batch { get; set; }
[Include]
[Composition]
[Association("FK_BathSetItemSet_ItemSet", "BatchSetIdItemSetId", "ItemSetId")]
public ItemSet ItemSet { get; set; }
}
public class ItemSet
{
public int ItemSetId { get; set; }
public int CustodianId { get; set; }
public string ItemSetName { get; set; }
public virtual ICollection<BatchSetItemSet> BatchSetItemSets { get; set; }
[Include]
[Composition]
[Association("FK_ItemSet_Custodian", "ItemSetId", "CustodianId")]
public virtual Custodian Custodian { get; set; }
}
and service call is : this.DbContext.Batches.Include("BatchSetItemSets.ItemSet.Custodian").Where(x => x.BatchId == batchId).SingleOrDefault();
You are close with the attributes, but they need to be changed:
[HasSelfValidation]
public class Batch
{
public int BatchId { get; set; }
public string BatchName { get; set; }
[Include]
[Composition]
[Association("FK_Batch_BathSetItemSet", "BatchId", "BatchId", IsForeignKey = false)]
public virtual ICollection<BatchSetItemSet> BatchSetItemSets { get; set; }
}
public class BatchSetItemSet
{
public int BatchSetIdItemSetId { get; set; }
public int BatchId { get; set; }
public Nullable<int> ItemSetId { get; set; }
public string CreatedBy { get; set; }
[Include]
[Association("FK_Batch_BathSetItemSet", "BatchId", "BatchId")]
public Batch Batch { get; set; }
[Include]
[Association("FK_BathSetItemSet_ItemSet", "ItemSetId", "ItemSetId")]
public ItemSet ItemSet { get; set; }
}
public class ItemSet
{
public int ItemSetId { get; set; }
public int CustodianId { get; set; }
public string ItemSetName { get; set; }
[Include]
[Composition]
[Association("FK_BathSetItemSet_ItemSet", "ItemSetId", "ItemSetId", IsForeignKey = false)]
public virtual ICollection<BatchSetItemSet> BatchSetItemSets { get; set; }
[Include]
[Association("FK_ItemSet_Custodian", "CustodianId", "CustodianId")]
public virtual Custodian Custodian { get; set; }
}
The AssociationAttribute .ctor is defined as:
AssociationAttribute(string name, string thisKey, string otherKey)
It should be configured as:
name: A unique name shared by each end of the relationship
thisKey: The name of the Property on this object that represents the key or foreign key
otherKey: The name of the Property on the other object that represents the key or foreign key
IsForeignKey: A property on AssociationAttribute to indicate if this end of the relationship is the primary key or the foreign key. It defaults to true (meaning this navigation property is a Foreign Key). By setting it to false, you indicate to WCF RIA that this object contains the Primary Key. For all AssociationAttribute usages with a given name, only one is allowed to have IsForeignKey = false. Otherwise, you will get a build error.
I've got a definition like below and essentially, I want to create this in the EmailAccount class:
public EmailUser? EmailUserAccountInfo {get;set;}
the compiler gives me an error about non-nullable types. My goal is I want to make the EmailUser optional. I'm kind of confused because I can set EmailUserAccountInfo = null directly.
var r = new EmailAccount()
{
EmailUserAccountInfo = null,
Id = 1001
};
public class EmailAccount
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public EmailUser EmailUserAccountInfo { get; set; }
}
public class EmailUser
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public EmailAccount EmailAcount { get; set; }
public string EmailAddress { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string ZipCode { get; set; }
public string City { get; set; }
public string State { get; set; }
public int Temperature { get; set; }
public string WeatherString { get; set; }
public ImageDetail ImageOfUser { get; set; }
}
You can do this if you add a foreign key and you mark that nullable:
public class EmailAccount
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
// Foreign key
public int? EmailUserAccountInfoId { get; set; }
// Navigation property
public virtual EmailUser EmailUserAccountInfo { get; set; }
}
See this document about naming conventions for Code-First. (Scroll down to Relationship Convention)