Assuming I have a child
public class Child
{
public int Id {get; set;}
}
and two parents which using the childs in one to one relations.
One child should be used only at one parent. But I want to use the child with Id=1 at ParentA and the child with Id=2 at ParentB for example.
public class ParentA
{
public int Id {get; set;}
public int ChildId {get; set;}
public Child Child {get; set;}
}
public class ParentB
{
public int Id {get; set;}
public int ChildId {get; set;}
public Child Child {get; set;}
}
I want the navigation property at the parents if possible.
I know how to configure a one to one relation when having only one parent because then I would have to add a navigation property in the Child class and would add the configuration in the OnModelCreating method of my DbContext implementation.
But for the scenario with 2+ parents I don't know how the configuration in OnModelCreating should look like.
Based on the additional info from the comments that the ParentA and ParentB are not mapped to the same table you could implement 2 one-to-one relationships resulting in:
public class Child
{
public int Id {get; set;}
public ParentA A {get; set;}
public ParentB B {get; set;}
}
This would mean that when A is initialized B is null and vice versa.
Alternatively if ParentA and ParentB are similar enough and it makes sence to have a common inheritance:
public class Child
{
public int Id {get; set;}
public Parent {get; set;}
}
public class Parent
{
public int Id {get; set;}
public int ChildId {get; set;}
public Child Child {get; set;}
}
public class ParentA : Parent { }
public class ParentB : Parent { }
And have the one-to-one relationship mapped between Parent and Child
This might also require DB changes.
Related
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.
I store my data with this data structure in Elasticsearch:
class Parent {
public guid Id {get; set;}
public string Name {get; set;}
public string Description {get; set;}
public List<Child> Children {get; set;}
}
class Child
{
public float Score{get; set;}
public int QTY {get; set;}
public string Name {get; set;}
}
Now I want to find the parents who have a child with a Score more than 6 and QTY more than 4. How can I provide the property Path of this fields in my query. I didn't store children as nestet object in the parent.
I am trying to work out how to add a reference an object from within EF.
I little hard to explain so I thought I would share a dotnetfiddle example
https://dotnetfiddle.net/4n5Flk
public class ReportConfig
{
[Key]
public int ReportConfigKey {get; set;}
public int ConfigTypeKey {get; set;}
public int ConfigValue {get; set;}
[ForeignKey("ConfigTypeKey")]
public virtual <ConfigType> ConfigType {get; set;}
}
public class ConfigType
{
[Key]
public int ConfigTypeKey {get; set;}
//This can be
//Address
//Car etc etc.
public string ConfigName {get; set;}
}
public class Car
{
[Key]
public int CarId {get; set;}
//other items
}
public class Address
{
[Key]
public AddressId {get; set;}
}
In a nutshell I am trying to create a navigation property to either a car or an address based on the ConfigValue and the ConfigTypeKey
I was thinking to create 2 navigation properties "Car" and "Address" and for both add 2 foreign key's 1 to the object and 1 as a hardcoded reference to ConfigName as Car or Address
is this possible atall
Sorry for the poor explanation.
Assume following model
class Order()
{
public int Id {get; set;}
public List<OrderItem> Items {get; set;}
}
class OrderItem()
{
public int Id {get; set;}
public string Name {get; set;}
}
So I have an order that has 10 items, now I need to build a query that returns all Orders that have the last item in their collection property Items having Name equals to specific value. How do I do that?
I have the following models:
public class Order
{
public int Id {get; set;}
public int CustomerId {get; set;}
public virtual Category Category {get; set;}
//Many more properties...
}
public class OrderLine
{
public int Id {get; set;}
public int OrderId {get; set;}
public virtual Order Order {get; set;}
public virtual Product Product {get; set;}
//Other properties...
}
I need to get the orders of a particular customer. In order not to retrieve too many information, I created a class:
public class CustomerOrder
{
public int CustomerId {get; set;}
public int OrderId {get; set;}
public string ProductName {get; set;}
public virtual ICollection<OrderLine> {get; set;}
}
I have mapping configuration for the Order and OrderLine classes but none for CustomerOrder as I was thinking that I can project data into this class.
I can:
Use EF to retrieve the data by specifying includes. After the data is retrieved I can project it into the CustomerOrder class. However, will this force EF to retrieve all columns for the main and included tables?
Use a custom SQL query to retrieve the required details from the Order table (maybe directly from a view). The use Linq to join this resultset with OrderLine to have the complete projection. However, will I need to have mapping configuration for the view?
To avoid too many columns and join in the SQL select statement, what is the best way to project the data into CustomerOrder?
You can do it as shown below.You have to do some changes on your models as well.I have done that.Please see that too.
public class Order
{
public int Id {get; set;}
public int CustomerId {get; set;}
public virtual Category Category {get; set;}
public virtual ICollection <OrderLine> OrderLines {get; set;}
//Many more properties...
}
public class OrderLine
{
public int Id {get; set;}
public int OrderId {get; set;}
public virtual Order Order {get; set;}
public virtual Product Product {get; set;}
//Other properties...
}
public class CustomerOrder
{
public int CustomerId {get; set;}
public int OrderId {get; set;}
public string ProductName {get; set;}
public virtual ICollection<OrderLine> OrderLines {get; set;}
}
Final Query :
var orderList = (from order in _context.Orders
from orderLine in order.OrderLines)
select new CustomerOrder
{
CustomerId = order.CustomerId,
OrderId = orderLine.OrderId,
ProductName= orderLine.Product.ProductName,
OrderLines = order.OrderLines
}).AsNoTracking().ToList();
A 1 : No.Only the projected columns will be fetched from the db.
Best Approach : Always use the custom projection (like CustomerOrder).That is the best when we consider the Performance of the EF query.You can use that to send data to the View too (it's like a DTO (Data Transfer Object)).