How to map in EF Core a collection of child entities when children has not ID of the parent? - entity-framework-core

I have this:
Class Order
{
long ID;
...
}
Class Item
{
long Id;
IdProduct;
decimal Amount;
...
}
How could I map this in EF Core using fluent API? Or is it not possible and I have to have in the childs a property for the ID of the parent? But in my case, from a point of view of DDD I don't need this property in the children because the children has not need to know about the parent.
Thanks.

Assuming you have a collection of 'Item' in Order ...
class Order
{
public long ID { get; set; }
public List<Item> Items { get; set; }
}
Order Config:
builder.HasMany<Item>(p => p.Items)
.WithOne()
.HasForeignKey("OrderId");
This will create FK property OrderId on the Item without it being explicitly declared in the class itself.

Related

Eagerly/explicitly load "child" entities with only navigation property to "parent"

I have an EF Core 2.1 Code First model with a "parent-child" type relationship between two classes:
class Parent
{
public int Id {get; set;}
public string Name {get; set;}
}
class Child
{
public int Id {get; set;}
public string Description { get; set; }
public Parent Parent { get; set; }
}
I want to load a certain Parent, and make sure that all its Child entities are loaded too. However, there is no navigation property to Child, and I cannot modify the classes, so I can't add one.
dbContext.Parents
.Include(p => p.???)
.Find(1);
I suppose I could do a second query where I look everything up in reverse:
dbContext.Children.Where(c => c.Parent.Id == loadedParent.Id)
but that does not seem very efficient, especially when you load multiple parents and do something horrible like this:
var parentIds = loadedParents.Select(p => p.Id);
var children = dbContext.Children.Where(c => parentIds.Contains(c.Parent.Id));
Is there a way to make sure entities are loaded when you only have a "child-to-parent" navigation property?
make sure that all its Child entities are loaded too
So load the Child entities:
var children = dbContext.Children.Include(c => c.Parent)
.Where(c => c.Parent.Id == 1).ToList();
Or use wider selection criteria than c.Parent.Id == 1 if you want to get multiple parents.
If necessary you can list the loaded parents by accessing the Local collection:
va parents = dbContext.Parents.Local;

How does Linq Where(p => p.Parent == null) work in self-referencing table?

Using EF 2.0 Core, code first, I have the following entity which defines a self-referencing table:
class EntityX
{
public int EntityXId { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
//navigation properties
public EntityX Parent { get; set; }
public ICollection<EntityX> Children { get; set; }
}
I want to retrieve all EntityX objects and their children in the form of a 'tree'
I can do that using:
var entities = context.EntityX
.Include(p => p.Parent)
.Include(p => p.Children)
.Where(p => p.Parent == null);
When I call entities.ToList() this gets me what I want: a list of parent entities with their children edit only 'first' generation children. When I omit the Where() clause, I get all entities and their children.
I do not understand why the Where() clause works. Objects that are part of the Children collection have a Parent. Why are they not omitted?
Edit: my question was answered but please be aware that I was wrong in my perception of how Include() works.
LINQ applies Where condition only to the objects in the collection being queried. Whatever else you choose to load with the Include method is not subject to the same condition. In fact, EF provides no direct way of restricting the associated entities (see this Q&A).
That is how the top-level query brings you what you expected. EF retrieves the children recursively via a separate RDBMS query using the parent ID to get all its children. The restriction from the Where method does not make it to the child query.

EF Model with collection and navigation to a particular element

How to configure a EF6 migration with a model class having?
A collection o items
A navigation property to one particular item
public class MyModel
{
[Key]
public int Id { get; set; }
// My collection of elements
public virtual ICollection<MyCollectionElement> MyCollection { get; set; }
// Optional navigation to a particular element from the collection
[ForeignKey("CurrentElement")]
public int? CurrentElementId { get; set; }
public virtual MyCollectionElement CurrentElement { get; set; }
}
public class MyCollectionElement
{
[Key]
public int Id { get; set; }
// Required navigation to MyClass
[ForeignKey("MyModel")]
public int MyModelID { get; set; }
public virtual MyModel Model { get; set; }
}
Configuration
modelBuilder.Entity<MyModel>()
.HasMany(x => x.MyCollection)
.WithRequired(x => x.Model)
.HasForeignKey(x => x.MyModelID)
.WillCascadadeOnDelete(false);
Throws several errors on Update-Database, like
Unable to determine a valid ordering for dependent operations.
I would like a solution which doesn't involve a boolean IsCurrent in MyCollectionElement to make another query later and find which element is the current; instead, I would like to store the current element's id with my model, like exposed.
Also, I don't mind making int CurrentElementId non nullable (required) if it's easier.
Thanks.
This chicken-and-egg problem always looms when there are circular relationships. The error...
Unable to determine a valid ordering for dependent operations.
...is not thrown when the database is created. The database can be created just fine. It occurs when you try to insert a MyModel record and a MyCollectionElement referring to one another in the same unit of work. In the Seed method you probably have something like
var element = new MyCollectionElement();
var model = new MyModel();
model.MyCollection.Add(element);
model.CurrentElement = element;
The statement model.MyCollection.Add(element); requires model to be inserted first, so element can refer to it in its foreign key. But model.CurrentElement = element; requires element to be inserted first.
You can only avoid this situation by calling SaveChanges twice, and wrapping everything in a TransactionScope if you want the assignments to be transactional:
using(var ts = new TransactionScope())
{
using(var db = new MyContext()
{
var element = new MyCollectionElement();
var model = new MyModel();
model.MyCollection.Add(element);
db.MyModels.Add(model);
db.SaveChanges();
model.CurrentElement = element;
db.SaveChanges();
}
ts.Complete();
}
This also means that int CurrentElementId should remain nullable.

Accessing data in Entity Framework relationship tables

I am trying to access the data in the relationship table created by
Entity Framework: I have two tables (posting the corresponding models here)
I have models for Event and Child, but not for ChildEvent.
Each Event has multiple children and each Child has multiple events as it is a many-to-many relationship. Now I am able to add and delete the entries into the tables. But when I am trying to access the children associated with each event, I am getting a null.
I have tried googling and I found some posts on easy loading. I have tried turning that off but the problem persists still. Is there any way I can get the children associated with each event. I do not have a model for ChildEvent? I cannot directly query the ChildEvent table.
Public Class Event { // This is the event model
public int EventId // This is the primary key
public int EventName
public virtual ICollection<Child> Children // used to reference Child table
}
Public Class Child { // This is the Child Model
public int ChildId // primary key
public string FirstName
public virtual ICollection<Event> Events // used to refer to Event table
}
I have the relationship table created the by Entity Framework
ChildEvent:
public int ChildId { get; set; }
public int EventId { get; set; }
This will ensure that Entity Frameowrk knows how you want your Many To Many relationships setup. This way Lazy Loading will work and EF will map Events to Children and Children to Events.
public class EventMap: EntityTypeConfiguration<Event>
{
public EventMap()
{
HasMany(e => e.Children)
.WithMany(c => c.Events)
.Map(m =>
{
m.MapLeftKey("EventId");
m.MapRightKey("ChildId");
m.ToTable("Event_Children");
});
}
}

Entity framework, find method leaves foreign key empty

I have an entity named PageItem. PageItem has a property named Page. Type of Page is Page class.
class PageItem {
public Page Page { get; set; }
...
}
when I query like this:
var item = context.PageItems.Find(5);
Problem is, item.Page is null, so when I save item entity framework creates a new page record.
Summary of what I learned:
First: entity framework Find method does not fill Id value of nested objects (in database language: foreign keys. But I realized than when you save that entity, it does not update foreign key columns, so nothing is broken.
Seconly: if you want to read, and use foregin key values of an entity, you should define (int/long whatever) properties per referanced table an foreign key. And mark it with ForeignKey attribute. Also if it can be null, make property type int? or long? (nullable)
Sample:
pubclic class Customer {
public Id { get; set; }
[ForeignKey("City")}
public int? City_Id { get; set; }
public City City { get; set; }
}
Also if you want layz loading on City, you have to mark it virtual.