Why are #OneToMany relationships are duplicated? - jpa

I have a 'save()' method inside a Session EJB (UpdateService) which persists an JPA Entity Bean.
The method first removes all existing #OneToMany relations to the Entity Bean. Than the method creates new relations and persists them. This all works so far as expected.
But now I have a situation, where another Session EJB (SuperService) which is calling my first Session Bean (UpdateService) needs to update a specific JPA Entity Bean twice. So during one transaction the method UpdateService.save() is called twice for the same entity.
I can see, that in this case the second call of UpdateService.save() did not recognize that the first call has created new relationship (which - as a result, will not be removed) and so it creates an additional relationship. As a result the relationship is doubled. The magic thing is, that other data which is part of attributes of my entity bean are already updated in the second call. It seems that only the pending new relationships are not removeable.
I played already with setting the TransactionIsolation to TRANSACTION_READ_UNCOMMITTED, but with no effect.
So my question is: how can I see that my entity has uncommited new relationships so that I can remove them?
I am running EclipseLink 2.5 on WildFly with MySQL.
This is a simplified part of my EJB code:
....
manager.setFlushMode(FlushModeType.COMMIT);
...
activeEntity = manager.find(Entity.class, sID);
// remove current TextItem List
for (TextItem aItem : activeEntity.getTextItems())
manager.remove(aItem);
activeEntity.getTextItems().clear();
..
// update the relationships
for (Object asingleValue : valueList) {
TextItem newItem = new TextItem(index.getName(),
asingleValue.toString());
manager.persist(newItem);
activeEntity.getTextItems().add(newItem);
}
manager.flush();
manager.detach(activeEntity);
return statusResult;

Related

How do i delete single record from table using EF 6.1.1

I am using Entity Framework 6.1.1.
I am deleting single record from table as following but i am not sure whether its the only way or could further rewrite it in an efficient way.
Can someone share comments?
Reason: I am asking because many solutions in earlier posts are referring to EF 4.0 and not using the latest version 6.1.1.
Guid studentId = student.Id;
StudentReportDetail stuDetails = _context.StudentReportDetail.Find(studentId);
if (stuDetails != null)
{
_context.StudentReportDetail.Remove(stuDetails);
_context.SaveChanges();
}
There are no changes about how to delete an entity between EF 4 and EF 6. To delete an entity using Entity Framework, you need to use the Remove method on DbSet. Remove works for both existing and newly added entities.
Calling Remove on an entity that has been added but not yet saved
to the database will cancel the addition of the entity. The entity is
removed from the change tracker and is no longer tracked by the
DbContext.
Calling Remove on an existing entity that is being change-tracked
will register the entity for deletion the next time SaveChanges is
called.
Deleting with loading from the database
As the example you show in your question, you need to load first the existing entity from your context to delete it. If you don't know the Id, you can execute a query as I show below to find it first:
var report= (from d in context.StudentReportDetail
where d.ReportName == "Report"
select d).Single();
context.StudentReportDetail.Remove(report);
context.SaveChanges();
Deleting without loading from the database
If you need to delete an entity, but it’s not already in memory, it’s a little inefficient to retrieve that entity from the database just to delete it. If you know the key of the entity you want to delete, you can attach a stub that represents the entity to be deleted, and then delete this stub. A stub is an instance of an entity that just has the key value assigned. The key value is all that’s required for deleting entities.
var toDelete = new StudentReportDetail {Id = 2 };
context.StudentReportDetail.Attach(toDelete);
context.StudentReportDetail.Remove(toDelete);
context.SaveChanges();
Other way could be changing the entity's state to Deleted.DbContext has methods called Entry and Entry<TEntity>, these methods get a DbEntityEntry for the given entity and provide access to the information about the entity and return a DbEntityEntry object able to perform the action on the entity. Now you can perform the delete operation on the context by just changing the entity state to EntityState.Deleted:
var toDelete = new StudentReportDetail {Id = 2 };
context.Entry(toDelete).State = EntityState.Deleted;
context.SaveChanges();
Using a 3rd party library
There is another way but is using a 3rd party library, EntityFramework Plus, there is a nugget package you can install. You can use the batch delete operation:
context.StudentReportDetail
.Where(u => u.Id== stuDetails)
.Delete();

DTO/POCO with Entity Framework

I'm using EF5 Model First. I don't really understand what are the auto-generated classes from the EDM. According to some documentation this classes are POCOs but why are they used in the context ?
Assuming I have a Student entity, then I get a Student POCO class and a DbSet StudentSet property in my context.
Will this next instructions put a POCO in my database ?
MyContext.StudentSet.Add(johndoe);
MyContext.SaveChanges();
So EF uses POCO to transfer data ? Actually I miss the step when POCO exchange data with entities or DTO and when the entities put data in the database.
The generated classes from the EDM is the ORM / Persistence classes. You use that classes to query / make changes from / to database. You need to translate any DTO object to POCO object when about making changes to database.
ORM is about mapping object to data in database, instead of dealing with insert into syntax to insert record to database in the application, you use StudentSet.Add to add a new data. The johndoe information will be translated into sql syntax, EF will map each property to each column when translating it into query.
The Add method will store the johndoe information as Added in the memory but it will not be executed right away to the database. If you have another Add method, it will be marked as Added too. The moment you call SaveChanges, all the changes will be saved into database by sending a generated query.
The mapping between DTO and EF entity happens before you add the johndoe. You might have another DTO class that is used in the UI. You need to map it manually or using mapper library to create a POCO object from a DTO object. For example:
// studentDto as parameter
var johndoe = new Student
{
Name = studentDto.StudentName,
Age = studentDto.StudentAge
};
MyContext.StudentSet.Add(johndoe);
// studentDto might have another information as well
var johndoeSubject = new Subject
{
Name = studentDto.SubjectName,
Years = studentDto.SubjectYears
};
MyContext.SubjectSet.Add(johndoeSubject);
MyContext.SaveChanges();

Entity Framework 5 Foreign Key New Record on SaveChanges

I'm using .NET4.5/EF5 and have created the model from an existing database.
I'm using the following code:
Order currentOrder = new Order();
using (var db = new ILSEntities())
{
try
{
Event currentEvent = db.Events.OrderByDescending(u => u.EventID).FirstOrDefault();
currentOrder.Event = currentEvent;
db.Orders.Add(currentOrder);
db.SaveChanges();
And I'm seeing that a duplicate record is being created of the Event object I find, which is not what I wanted to happen.
I've read a lot of posts relating to similar problems, but where the context of the two participants in the foreign key relationships are different. Here, I'm saving with the same context I use to find one, and the other object is new.
I've also tried:
currentOrder.Event.EventID = currentEvent.EventID;
but that fails as well as I get an EF validation error telling me it needs values for the other members of the Event object.
I've also tried specifically setting the EntityState of the object being duplicated to Detached, Modified etc. after adding the Order object but before SaveChanges without success.
I'm sure this is a basic problem, but it's got me baffled
In my understanding, both parent and child objects have to be in the context before you assign any relationship between them to convince the entity framework that an entity exists in the database already. I guess you are trying to add new Order object to Database, to add new object you should be using AddObject method, Add() method is used to establish relation between entitties. In your code, currentOrder is not in the context. Try to hook it in the same context and then assign a relation. Your code should look like this :
Order currentOrder = new Order();
using (var db = new ILSEntities())
{
try
{
Event currentEvent = db.Events.OrderByDescending(u => u.EventID).FirstOrDefault();
db.Orders.Attach(currentOrder); //attach currentOrder to context as it was not loaded from the context
currentOrder.Events.Add(currentEvent);//establish relationship
db.ObjectStateManager.ChangeObjectState(currentOrder, EntityState.Added);
db.SaveChanges();
}
}
OK, I did in the end figure this out, and it was my fault.
The problem was that the Order object is FK'd into another table, Shipments, which is also FK'd into Events. The problem was that it was the Event reference in the Shipment object that was causing the new record. The solution was to let EF know about these relationships by adding them all within the same context.
The code assembling the object graph was spread over a number of webforms and the responses here made me take a step back and look at the whole thing critically so whilst no one of these answers is correct, I'm voting everybody who replied up

MS EntityFramework: how to split entity with inheritance?

I have table name Transaction in the DB. I want to have 2 subclasses TransactionA and TransactionB. I've made it as described here: http://www.robbagby.com/entity-framework/entity-framework-modeling-table-per-hierarchy-inheritance/comment-page-1/#comment-607
As I use T4 templates I've generated self-tracking entities.
Everything is okay but one thing. I can see generated entities TransactionA and TransactionB but I cannot see them in the context object (ObjectContext). Is it normal? If so, how could I get TransactionB from the table using context if only Transaction class is accessible?
Thanks
This is as expected. Transaction A en B derive from the baseclass Transaction. In your entity model you can access them through the collection of Transactions like this:
Context context = new Context();
List<TransactionB> list = context.Transactions.OfType<TransactionB>().ToList();

Adding object to navigation property collection creates new entity

I am using Entity Framework 4.
I am trying to associate a new entity with an existing entity. The system ends up creating a new child entity when in fact I just want to add a reference to the child object to the parent.
There is a many to many relationship between the two entities so I cannot simply set the FK property of the parent entity. I have tried parent.ChildCollection.Add(child) which simply creates a new child object in the database. This is what I am trying to avoid.
I must be doing something obviously wrong.
thanks
updated code sample
Code sample for my Self-Tracking-Entities that I have to do client side
Right now I have something like this to get all children from server then loop through to find the one i want, then add it to the object collection
List<Service.Child> childs = _client.GetChildren();
I have to loop through that collection to find the right one to add to the parent.childs collection ie.
List<Service.Child> childList = new List<Service.Child>();
foreach (Service.Child child in childList) {
if (child.ChildId == childId)
childList.Add(child);
}
contact.Childs = childList;
If an entity originally came from the database and has its own EntityKey properties populated, using Add to link it to another entity will change its EntityState to Added. Even though it is a preexisting entity, SaveChanges will create an insert command for this entity. You should consider using Attach instead:
parent.ChildCollection.Attach(child);
Using the Attach method, you can define relationships between entities that already
exist in the ObjectContext but that have not been connected automatically.