EF ObservableListSource Specify ForeignKey - c#

I have two entities: Employee & Contract.
In the Contract entity I have the properties AddedByEmployee & AssignedToEmployee.
I want a collection navigation property in my Employee class but how do I reference the correct key in the Contract class?
So far I have:
public class Employee
{
public int EmployeeID {get; set;}
public string Name {get; set;}
private readonly ObservableListSource<Contract> _Contracts = new ObservableListSource<Contract>();
public virtual ObservableListSource<Contract> Contracts { get { return _Contracts; }
}
public class Contract
{
public int ContractID {get; set;}
public string Name {get; set;}
public int AddedByEmployeeID {get; set;}
public int AssignedToEmployeeID {get; set;}
[ForeignKey("AddedByEmployeeID")]
public virtual Employee AddedByEmployee { get; set; }
[ForeignKey("AssignedToEmployeeID")]
public virtual Employee AssignedToEmployee { get; set; }
}
So basically: How do I let the ObservableListSource<Contract> know it is the AddedByEmployeeID I want to map to?
Thanks

You can do this by either using DataAnnotations or the Fluent API.
Doing it with DataAnnotations you can add the InverseProperty attribute to either your Contracts or AddedByEmployee property (or both, but that is not necessary).
This will tell Entity Framework that a relationship should be made between Contracts and AddedByEmployee.
[InverseProperty("AddedByEmployee")]
public virtual List<Contract> Contracts
{
get { return _Contracts; }
}
If you want to use the Fluent API instead, you simply have to explicitly define the relationship like this:
modelBuilder.Entity<Employee>()
.HasMany(p => p.Contracts)
.WithRequired(p => p.AddedByEmployee)

Related

Mapping a single navigation property in EF Core

I am working on a project which involves EF Core.
I would like to use the foreign keys from Category with one single navigation property.
Therefore, Item stores the foreign keys of Category, and the names of the Category can be shown.
This is how the relationship looks like:
Classes:
[Table("Item" , Schema = "public")]
public class Item
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ItemID {get; set;}
public string Name {get; set;}
public int CategoryID {get; set;}
//Single Navigation Property
public Category Category {get; set;}
}
[Table("Category" , Schema = "public")]
public class Category
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CategoryID {get; set;}
public string Name {get; set;}
}
DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Item>().ToTable("Item");
modelBuilder.Entity<Category>().ToTable("Category");
modelBuilder.Entity<Item>()
.HasOne(i=>i.Category)
.WithOne()
.HasForeignKey<Item>(i=>i.CategoryID);
}
It shows an error
Duplicate key value violates unique constraint "IX_ItemDB_CategoryID"
Apparently, it means CategoryID cannot be duplicate in Item.
What am I doing wrong here? Thanks!
actually your answer in this article. What you need to do is change the location of the navigation property. So Item should not have an Category property, Category should have a collection of Item for single navigation. the article describes other ways.
In case I understand properly You need one to many relation and I can offer you that structure and if you use Migration your tables will be properly build in the database. No to do anything in the FluentApi to, Your FK, PK(identity) and Indexes will be automatically created
[Table("Item" , Schema = "public")]
public class Item
{
public int Id {get; set;}
public string Name {get; set;}
public int CategoryId {get; set;}
public Category Category {get; set;}
}
[Table("Category" , Schema = "public")]
public class Category
{
public Category()
{
this.Items = new HashSet<Item>();
}
public int Id {get; set;}
public string Name {get; set;}
public virtual ICollection<Item> Items {get; set;}
}
Ivan Stoev is correct. The model of my question is fine and fluent configurations are not required. EFCore will handle the rest.

AutoMapper with nested objects and container class

I'm developing an API with .NET core and using AutoMapper.
all the API responses will be wrapped with a data element in the JSON response like below example
GET User
{
"data" {
"id" : 1,
"user_name": "abc"
"countryr" : {
"id" : 1348,
"code" : "USA"
}
}
}
So we have an entity for User and Country
public partial class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public virtual Country country { get; set; }
}
public partial class Country
{
public int Id { get; set; }
public string Code{ get; set; }
}
To map entities to DTO we have below reponseDTO
public class GetUserDTO {
public User data {get; set;} // To wrap reponse with data
}
public class UserDto {
public int id {get; set;}
public String user_name {get; set;}
public Country country {get; set;}
}
public class CountryDto {
public int id {get; set;}
public String code {get; set;}
}
As per my understanding , I should map the entity User to the UserDTO and Country entity to CountryDTO but what about GetUserDTO class itself? it basically contains other entities so the class itself cannot be mapped to anything it acts like a container.
So below what I did so far which is not correct
public class UserProfile : AutoMapper.Profile
{
public MappingProfile()
{
CreateMap<User, GetUserDTO>();
CreateMap<User, UserDto>()
.ForMember(userDto => userDto.user_name, map => map.MapFrom(user => user.FirstName))
CreateMap<Country, CountryDto>();
}
}
Json response
{
"data" : null
}
What to do for such situations?
You should not refer your entity classes in your DTO classes. You might want to change the DTO as below.
public class GetUserDTO {
public UserDto data {get; set;} // To wrap reponse with data
}
public class UserDto {
public int id {get; set;}
public string user_name {get; set;}
public CountryDto country {get; set;}
}
public class CountryDto {
public int id {get; set;}
public string code {get; set;}
}
And then in the Mapper profile, you need to explicitly map each property as cases are different(AutoMapper will map without explicity map if the names are exactly the same. In your example, there is a case difference)
And then remove the below line from the MapperProfile as there is no mapping from the User class to GetUserDTO class. This is the reason you are not getting any output.
CreateMap<User, GetUserDTO>();
While getting the data, you should create a new instance of GetUserDTO class and set the property "data" from the result of mappaing of the User object.
This will get you the output.

Entity Framework code first for object with collection of properties

I'm using C# and .NET Core with MySql and Entity Framework.
I have an object with a collection of properties. Like this:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<Property> Properties { get; set; }
}
public class Property
{
public int Id { get; set; }
public string Name { get; set; }
public object Value { get; set; }
}
In this case in the database, I should have tables Products, Properties (where property is described, like name and some additional info), and link table ProductProperties, storing product Id, property Id and Value.
But I can't figure out how to do this with a code-first approach.
How could I implement it with code first?
Is it a good way to create one more entity PropertyValue and store it under Product?
Something like this should give you a 1-to-many relationship, although you need to give Value a type, like string to store it in the database, often for dynamic solutions like this you would then maybe add a type to specify the type to deserialize into, but since you then deserialize anyway you could also just add things as json or something else in the db.
public class Product
{
public int Id {get; set;}
public string Name{get; set;}
public ICollection<Property> Properties{get; set;}
}
public class Property
{
public int Id {get; set;}
public string Name {get; set;}
public string Value {get; set;}
public int ProductId {get; set;}
}
Unless you are making a very dynamic system, it doesn't seem right to have the properties as a table, depends a lot of what you are making, and maybe key-value db might be a better tool for the job if thats what your main problem is, as with most complicated things, it depends.
This example is a convention based approach, which is why properties like ProductId have to be called exactly that. You can look at EntityTypeConfigurations if you want more control of names and relationships and such, or use data annotations to achieve the same job.
Ok so create a table like this:
public class ProductProprties
{
public int ProductId {get; set;}
public Product Product {get;set;}
public int PropertyId {get; set;}
public Property Property {get;set;}
//other props
}
If you are using EntityFramework Core, then you have to add this to your databse context as well:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ProdcutProprties>().HasKey(x => new { x.ProductId , x.PropertyId });
}

One to one relationship without reference property on one side

I have the following construct; a person with an address (ownsone, sub-entity) and an address with a country (hasone, one-to-one)
public class Person
{
public Guid Id {get; set;}
public string Name {get; set;}
public Address Address {get; set;}
}
public class Address
{
public Guid Id {get; set;}
public Guid CountryId {get; set;}
public Country Country {get; set;}
}
public class Country
{
public Guid Id {get; set;}
public string CountryCode {get; set;}
}
public class EntityConfiguration<Person> where Person : class
{
public void Configure(EntityBuilder<Person> builder)
{
builder.OwnsOne(p => p.Address, addressBuilder =>
addressBuilder.HasOne(address => address.Country).WithOne();
}
}
When I run Add-Migration I get a block of code for each entity which owns one address. With auto-generated keys and so on. But I want to specify the relation explicitly with HasForeignKey. How to do this?
EF Core provides 2 fluent APIs for one-to-one relationships - HasForeignKey and HasPrincipalKey.
The main difference with one-to-many APIs is that you need to explicitly provide the generic type argument, because the principal and dependent end of the relationship cannot be determined by the HasOne / WithOne calls (for one-to-many the one is always the principal and many is the dependent). The navigation properties in this case doesn't matter:
addressBuilder.HasOne(address => address.Country)
.WithOne()
.HasForeignKey<Address>(address => address.CountryId)
Reference: Relationships

one to many and self referencing in entity framework

I have two entities with following relationShip (these entities are taken for example purpose only)
public class Entity
{
public long ID { get; set; }
}
public class Doctor : Entity
{
public string Name {get; set;}
public string sprcialization { get; set;}
public string Icollection<JrDoctor> childDoctors { get; set;}
}
public class JrDoctor : Entity
{
public long? DoctorId { get; set;}
public virtual Doctor Doctor { get; set;}
public long? JuniorDoctorId { get; set;}
[ForeignKey("JuniorDoctorId")]
public virtual Doctor JuniorDoctor { get; set;}
}
this relationship in entityframework is creating an extra column Doctor_Id in JrDoctor table. Why is it so? and how can I avoid it using data annotations.
Here is how EF works - if it sees navigation property (Doctor in your case), then EF understands that both entities are related to each other. Relation in database is defined by foreign keys. So EF generates foreign key with name PropertyName_KeyColumnOfRelatedEntity. That's why you see column Doctor_Id in JrDoctor table.
If you don't want default generated foreign key column, then you should tell EF what it should use instead. That is done via data annotations attributes or fluent configuration. I prefer latter one:
modelBuilder.Entity<JrDoctor>()
.HasOptional(jd => jd.Doctor)
.WithMany(d => d.childDoctors)
.HasForeignKey(jd => jd.DoctorId); // here you tell which column is FK
Data annotations require modification of entity classes. In your case you should add attribute which tells name of FK for navigation property, just as you did for JuniorDoctor:
public class JrDoctor : Entity
{
public long? DoctorId { get; set;}
[ForeignKey("DoctorId")]
public virtual Doctor Doctor { get; set;}
public long? JuniorDoctorId { get; set;}
[ForeignKey("JuniorDoctorId")]
public virtual Doctor JuniorDoctor { get; set;}
}
InverseProperty did the trick.
public class Entity
{
public long ID { get; set; }
}
public class Doctor : Entity
{
public string Name {get; set;}
public string sprcialization { get; set;}
[InverseProperty("Doctor")]
public string Icollection<JrDoctor> childDoctors { get; set;}
}
public class JrDoctor : Entity
{
public long? DoctorId { get; set;}
[ForeignKey("DoctorId")]
public virtual Doctor Doctor { get; set;}
public long? JuniorDoctorId { get; set;}
[ForeignKey("JuniorDoctorId")]
public virtual Doctor JuniorDoctor { get; set;}
}

Categories

Resources