FOSElasticaBundle: ManyToMany relationship - foselasticabundle

I'm trying to use FOSElasticaBundle on my symfony 4 project and I have some problems.
I have an entity, "Users", with the next annotation in the property "segments":
* #var Collection $segments
* #ORM\ManyToMany(targetEntity="App\Entity\Segment", mappedBy="users", cascade={"persist", "remove"})
Which is the correct form to do the mapping in the fos_elastica.yaml file?

I would suggest you to think in your use cases and then decide which related entities are you going to use for search purposes. Once decided, you can do two things:
Option A, use a nested field. Is simpler but, if you update a child (related) entity, the Elasticsearch index will not be updated. Yo must ensure that this happens within your code. For example, each time the child entity gets updated, you set a timestamp in the parent entotity, so FosElasticaBundle catch's that chahge and runs the entity serializer so the child entity becomes serialized.
Option B, use a child parent relation in Elasticsearch. In this case FosElasticaBundle will track your entity changes correctly for each Doctrine entity, so you don't need to manage it in your code.
In both cases, you many to many relationship becomes in two one to many relations. In option A this is done by the serializers that embeds the child document in the parent one. In the second case it is tranlated to a parent child relationship.

Related

Remove entities and remove relationships on Entity framework

I´m using EF databaseFrist and creating a model, now having a problem trying to understand how to delete an entity or a relationship.
Lest say a have and Table "A" and a Table "B", and a "a_b" table that relates A and B by id (many to many), a_b only has id_A and id_B, so there is no entity a_b created on the model. A has a list<B> and B has a list<A>, i need to know how can i perform the next functions:
-Remove all B entities related to A, it means delete the rows of B.
-Remove only the relationships of A to B, so all entities still exist on DB but they are dissociated.
-Delete A and remove all B related as well (remove entities from DB).
-Delete A and preserve all B entities.
-How will it change if a_b has any other property so it becomes an entity
thanks for your time.
pd: I´m using Lambda syntax.
You can tell EF on DB First model creation to expose all primary and foreign-key properties in the entities. What it means to you is that you can query separately by querying for child objects to a parent by using the foreign-key property of the child object linked to the parent object's primary key. You can delete each child object to the parent by the child's primary-key property value to remove the relationship between parent and child. You can delete the parent if no child object is linked to the parent. That's if one is doing things normally in a deletion process using EF where one takes complete control of the deletion process.
So, you can kind of do something like that.

JPA Cascade ALL to skip unmodified entities

When we update a root entity with CASCADE.ALL option all the child objects also gets updated in JPA.
If I know before hand that a pariticular child entity is not modifed , is there a provision to denote in the entity that it is not modified , so that unnecessary update query is not fired.
We can very well exclude the particular child from the parent collection , so that JPA will not update anything .
I would like to know if there is any flag to denote at Entity level to specifiy that no properties are modified

EF anonymous object query returns null collections instead of empty ones

I'm using this trick to perform conditional Include's with EF. http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx
The problem I'm having is that any collections that don't have records, are null, and not empty. This is causing headaches cos I have to check each collection before I can loop through it in my mvc view, otherwise i get a null reference exception.
For example, the StudentModules collection will be null. How can I turn it into an empty list in my query? ie without having to loop through it all and checking.
I can put a constructor in the poco to initialize the list, which fixes it, but the this collection is a virtual member in the poco (based on an EF video!) - surely this is not the way to go?
var query = from module in db.Modules
where module.Id == id
select new
{
module,
QualificationModules = from qualificationModule in module.QualificationModules
where qualificationModule.IsDeleted == false
select new
{
qualificationModule,
qualificationModule.Qualification,
StudentModules = from studentModule in qualificationModule.StudentModules
where studentModule.IsDeleted == false
select new
{
studentModule,
studentModule.Student
}
},
Assessments = (from assessment in module.Assessments
where assessment.IsDeleted == false
select new
{
assessment,
assessment.AssessmentType
}
)
};
var modules = query.AsEnumerable().Select(x => x.module);
return modules.ToList().First();
Relationship fixup runs when an entity gets attached to a context - either manually by calling Attach or when the entity is materialized as a result of a query (your case).
It is based on foreign keys of an entity and works in both directions:
If the context already contains an entity A with a foreign key f to entity B and an entity B is being attached to the context that has a primary key with the same value f as the foreign key in A (i.e. the two entities are related by an FK relationship) then Entity Framework will do the following:
If A has a navigation reference property to B it will assign the attached entity B to this property.
If B has a navigation reference property to A (one-to-one relationship) it will assign A to this property.
If B has a navigation collection property to A (one-to-many relationship) it will add A to this collection in the attached entity B. If the collection is null it will instantiate the collection before adding.
If an entity B is being attached to the context that has a foreign key f to an entity A that the context already contains and that has f as primary key EF will set the navigation properties based on the same rules like above.
As a side note: The fact that relationship fixup is based on foreign keys (they are always loaded when you query an entity, no matter if the FK is exposed as property in the model class or not) is also the reason why relationship fixup does not apply to and does not work for many-to-many relationships because the two entities of a many-to-many relationship don't have a foreign key.
Now, if there are no related StudentModules in your case there is no StudentModule entity that gets loaded into the context and there is nothing what EF could target for a fixup. Keep in mind that the fixup algorithm is not related to a particular query and does not only fix relationships between entities that this query would materialize but it will consider all entities for fixup that the context already contains, no matter how they came into the context. If you would want that collections get instantiated as empty collections EF had run through all attached parent entities of StudentModules and just create an empty collection. It makes no sense to do this during fixup instead of creating empty collections up-front before entities get attached to a context.
I can put a constructor in the poco to initialize the list, which
fixes it, but the this collection is a virtual member in the poco
(based on an EF video!) - surely this is not the way to go?
In my opinion it is the best solution if you don't want to have null collections in your model class instances. It doesn't matter if the collection is declared as virtual (to enable lazy loading) or not. A collection type does not have a derived proxy type, only the instances that get added to the collection are derived proxies. In both case you can just use StudentModules = new HashSet<StudentModule>(); (or List if you prefer).

Is there a way to load only ID of entity/entities avoiding FetchGroup strategy ?

There some cases when loading of only ID of an entity or IDs of a collection of entities (in a relationship, for example) is needed. For example I have en entity Parent and a collection of children in it
class Parent {
private List<Child> children;
}
So, when I want to load children I want only the ids to be loaded for some cases, not whole state of children. I made a research and I found a way via Named FetchGroup, which means if I want to implement this I have to add for each Entity annotation #FetchGroup(name="id", attributes = {#FetchAttribute(name = "id")}). That work for the cases when I want to apply it for only an entity of course. For children case also LoadGroup should be configured.
The question here is: is there another strategy specially for loading of ONLY ID's, when an entity or entities are requested ? Or a way to indicate that ? Here I want to avoid annotation with #FetchGroup all entities I would like to applied that, just for loading of only ID. Of course, creation of a query like "SELECT ID FROM Parent WHERE ..." or "SELECT child.id FROM Parent INNER JOIN Parent.children WHERE ..." is also not a solution here since always should be defined, for all relationships and entities.
If you just want one entity, you can use getReference() on EntityManager.
If it is a query, or relationship, then fetch groups in EclipseLink is your only option.

How to use DBContext.Add/Attach (using EF CodeFirst 4.1) with nested opbjects

Problem: When adding an object "Order" to my dbcontext, all nested objects of the order gets "readded" to the database, though the nested objects is static data and only a reference shoudl be added in the database.
Example:
The database holds 0 orders, and 3 items.
I add one order with 2 items.
Now the database hold 1 order, and 5 items. The two items in the order has been "readded" to the database, even though the items had the right primary keys before db.SaveChanges().
I realize that i may be able to attach the existing items to the dbcontext before saving changes, but is that really the only way to go? Can't EF figure out that to item already exists when the primary key matches an existing item?
Does anyone know if this is different in the new version of EF CodeFirst?
No EF cannot figure if entities are existing one or new one - both Add and Attach commands are graph oriented operations. You call them on one entity in the graph and they traverse all relations (and their relations and so on) and perform the operation for them as well.
You must figure correct state of each entity in the graph for example by using:
dbContext.Orders.Add(newOrder);
foreach(var item in newOrder.Items) {
dbContext.Entry(item).State = EntityState.Unchanged;
}
dbContext.SaveChanges();
You can use the reverse operation by calling Attach(newOrder) and set the order to Added state. The main difference will come with independent associations (for example many-to-many relations). The first approach will correctly add new relation between order and each item whereas second will not unless you manually set each relation to Added state (and changing state for relations is more complex).