I am defining a class based on a cataloguing Authority entry, which has a number of self referencing children, as follows:
public class Authority
{
public long ID { get; set; }
public string Term { get; set; }
public string Language { get; set; }
public bool PreferredTerm { get; set; }
public TermStatus TermStatus { get; set; }
public Authority Use { get; set; }
public List<Authority> UsedFor { get; set; }
public List<Authority> Equivalent { get; set; }
public List<Authority> Broader { get; set; }
public List<Authority> Narrower { get; set; }
}
When the columns are created in the Authority table in the underlying SQL database, the column names for each of the List properties are Authority_ID, Authority_ID1, Authority_ID2 and Authority_ID3.
I would rather the column names to be 'UsedFor', 'Equivalent', 'Broader' and 'Narrower'. I have tried using the [Column("name")] attribute but it does not work. How can I do this in Code First?
Try this. I am not sure if the definitions of the foreign keys must be in the POCO class (you can try to omit them).
public class Authority
{
[Key()]
public long ID { get; set; }
public string Term { get; set; }
public string Language { get; set; }
public bool PreferredTerm { get; set; }
public TermStatus TermStatus { get; set; }
public Authority Use { get; set; }
[Required]
public long Authority_ID { get; set; }
[Required]
public long Authority_ID1 { get; set; }
[Required]
public long Authority_ID2 { get; set; }
[Required]
public long Authority_ID3 { get; set; }
[ForeignKey("Authority_ID")]
public ICollection<Authority> UsedFor { get; set; }
[ForeignKey("Authority_ID1")]
public ICollection<Authority> Equivalent { get; set; }
[ForeignKey("Authority_ID2")]
public ICollection<Authority> Broader { get; set; }
[ForeignKey("Authority_ID3")]
public ICollection<Authority> Narrower { get; set; }
}
You can use [InverseProperty("name")] for your list. After that, your column names will be "UsedFor_ID", "Equilavent_ID", etc in the database (not quite corresponding to your question, sorry!).
public class Authority
{
[InverseProperty("UsedFor")]
public List<Authority> UsedFor { get; set; }
[InverseProperty("Equivalent")]
public List<Authority> Equivalent { get; set; }
}
See more at: https://msdn.microsoft.com/en-us/data/gg193958 http://www.entityframeworktutorial.net/code-first/inverseproperty-dataannotations-attribute-in-code-first.aspx
Thanks for the suggestions. What worked was to use [ForeignKey] for the link and [Column] to rename the column, ie
[Column("Use")]
public long? UseID { get; set; }
[ForeignKey("UseID")]
public List<Authority> Use { get; set; }
However I have also made a critical mistake in the definition because even though I defined the column as a List, the code above ends up with a 1-to-0/1 key. What I really needed to do was to add in a child table to accept the many values.
My final code looks like this, and the underlying column names are readable instead of Authority_ID, Authority_ID1, Authority_ID2 and Authority_ID3:
public class Authority
{
public long ID { get; set; }
public string Term { get; set; }
public string Language { get; set; }
public bool PreferredTerm { get; set; }
public TermStatus TermStatus { get; set; }
//Establish 1-to-0/1 self-referencing key
[Column("Use")]
public long? UseID { get; set; }
[ForeignKey("UseID")]
public List<Authority> Use { get; set; }
//Establis 1-many foreign keys
[ForeignKey("UsedFor")]
public List<AuthorityList> UsedFor { get; set; }
[ForeignKey("Equivalent")]
public List<AuthorityList> Equivalent { get; set; }
[ForeignKey("Broader")]
public List<AuthorityList> Broader { get; set; }
[ForeignKey("Narrower")]
public List<AuthorityList> Narrower { get; set; }
}
public class AuthorityList
{
public long ID { get; set; }
public long AuthorityID { get; set; }
public long? UsedFor { get; set; }
public long? Equivalent { get; set; }
public long? Broader { get; set; }
public long? Narrower { get; set; }
}
In order to prevent cascading deletes getting in the way I have also added the following into my database context (affects entire DB not just these tables):
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
Updated answer :
Using the above gave me the underlying table structure I wanted but not the functionality I required since EF decided that under that configuration it was going to map a 1-1 relationship instead of 1-M. The answer lay in understanding how EntityFramework manages self-referencing Many-to-Many relationships. Even this can be configured multiple ways depending on whether you only want two 1-M relationships or more. I want six.
In the end, this configuration gave me the functionality I wanted, to the expense of having a less than ideal database structure.
public class Tag
{
public int ID { get; set; }
public string Term { get; set; }
public virtual ICollection<Tag> Broader { get; set; }
public virtual ICollection<Tag> Narrower { get; set; }
public virtual ICollection<Tag> Equivalent { get; set; }
public virtual ICollection<Tag> Related { get; set; }
public virtual ICollection<Tag> Use { get; set; }
public virtual ICollection<Tag> Usefor { get; set; }
public Tag()
{
Broader = new HashSet<Tag>();
Narrower = new HashSet<Tag>();
Equivalent = new HashSet<Tag>();
Related = new HashSet<Tag>();
Use = new HashSet<Tag>();
Usefor = new HashSet<Tag>();
}
}
I also needed to add the following entries into the 'OnModelCreating' procedure of the database context:
modelBuilder.Entity<Tag>()
.HasMany(x => x.Broader)
.WithMany()
.Map(x => x.MapLeftKey("TagID").MapRightKey("BroaderID").ToTable("TagBroader"));
modelBuilder.Entity<Tag>()
.HasMany(x => x.Equivalent)
.WithMany()
.Map(x => x.MapLeftKey("TagID").MapRightKey("EquivalentID").ToTable("TagEquivalent"));
modelBuilder.Entity<Tag>()
.HasMany(x => x.Narrower)
.WithMany()
.Map(x => x.MapLeftKey("TagID").MapRightKey("NarrowerID").ToTable("TagNarrower"));
modelBuilder.Entity<Tag>()
.HasMany(x => x.Related)
.WithMany()
.Map(x => x.MapLeftKey("TagID").MapRightKey("RelatedID").ToTable("TagRelated"));
modelBuilder.Entity<Tag>()
.HasMany(x => x.Use)
.WithMany()
.Map(x => x.MapLeftKey("TagID").MapRightKey("UsedID").ToTable("TagUse"));
modelBuilder.Entity<Tag>()
.HasMany(x => x.Usedfor)
.WithMany()
.Map(x => x.MapLeftKey("TagID").MapRightKey("UsedforID").ToTable("TagUsedfor"));
To test, I used the following:
//Broader/Narrower example
var music = new Tag{ Term = "Music"};
var jazz = new Tag{ Term = "Jazz Music" };
var classical = new Tag{ Term = "Classical Music" };
music.Narrower.Add(jazz);
music.Narrower.Add(classical);
jazz.Broader.Add(music);
classical.Broader.Add(music);
//Equivalent example
var zucchini = new Tag{ Term = "Zucchini" };
var courgette = new Tag{ Term = "Courgette" };
zucchini.Equivalent.Add(courgette);
courgette.Equivalent.Add(zucchini);
context.Tags.Add(music);
context.Tags.Add(jazz);
context.Tags.Add(classical);
context.Tags.Add(zucchini);
context.Tags.Add(courgette);
context.SaveChanges();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.