I have an entity A and an entity B that extends A.
let's say A is a basic profile and B is a more complete one.
I look up in the bd to find A and I have to cast it in B to be able to get the more advanced profile.
I've tried to downcast but then JPA complains about detached entity.
I've tried to use a constructor in B that takes A in arguments, but still JPA complains.
I'm trying to find more information about it withtout that many success.
A and B are in 2 different tables, but when I create B directly everything is fine (B and A having the same id in their own table)
Any idea how I can get a A and convert it in B and get JPA to work as expected ?
Thanks !
Related
We use Eclipselink-2.6 with wildfly-8 server in a JavaEE7 application.
we have three JPA entities A, B, and C.
B and C extend A.
In order to change the type of an object "myObjectId" A to B, we try to:
1- Change the dtype value from "a" to "b" in Table "A" for the instance "myObjectId" using the criteria query.
2- Create a new row in the table "B" in the database for the same id "myObjectId" also with a criteria query.
3- Clearing the cache by evictAll as well Entitymanger using clear functions.
After, when I tried to find all data of type B, the object "myObjectId" came in the list but with type A!
After restarting wildfly server and call findAll, therefore, the data came with type B!
why myObjectId didn't change its type even if the first and the second level cache was cleared!?
See https://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching
Essentially EclipseLink maps the JPA cache eviction call to its own invalidation logic, which seems to be keeping a reference to the object using a soft reference so that object identity is maintained. This prevents A1->B1->A1' from happening on cycles with lazy relationships.
Try calling ((JpaEntityManager)em.getDelegate()).getServerSession().getIdentityMapAccessor().initializeAllIdentityMaps() as suggested in the doc and then reading in the changed class.
I am having a problem when updating/merging an entity A which has a reference to another entity B. A also has a reference to an entity C.
I create a new instance of the entity A from a domain object. Also from this domain object I use the ids to get B and C by using entityManager.getReference(<class>, <id>). I call entityManager.merge and entityManager.flush(). So far all is good, the values of both B and C are present in A. When I after the flush do a entityManager.refresh(A), the B is cleared(null), but the C is still there.
I run sql queries to verify that the value is there before the update. After the flush the FK to B is cleared, so when the refresh is called it discovers this.
I do not know what to look for here. Might it be something with how my entities are defined? Persistence-xml? Any tips are much appreciated!
EDIT:
The value of B is only cleared if I do not change the reference. If I change the reference of B to B', then it is updated correctly
The question did not show the entire context of where I was experiencing the problem. The entity A which had a reference to B, also had the foreign key field in it. This foreign key field was always null, so setting the entity reference had no effect.
I have an ERD with a main table (A) which has one attribute(String) that is a FK to another table (B).
The issue that I have is that in B the only attribute is the PK; I just want to ensure that the user inputs only one of the allowed values in the main table attribute. I do not even want to update the B table from the application, as it will be a task so unusual that I'll do it directly in the DB.
I could treat B just as another Entity and deal with them with "regular" JPA, but I am a little troubled that maybe there are more efficient ways to do it*. All I want from B table is to get the full list of values and to ensure that the attribute value is correct.
So the question is: there is a specific pattern in JPA to deal with those master tables?
Thanks In advance.
*: My concern is creating / retrieving Entity B objects when all that it is needed is an string, every time an Entity A object is created retrieved.
I would simply use a native query to get all the strings from the B table, or map B as an entity to retrieve all the B Strings using a JPQL query, but not have any association from A to B.
The B string would be stored as basic String column in entity A. And if you try creating or updating an A instance with a string that is not in the B table, then you'll get an exception at flush or commit time because the foreign key constraint is broken.
I tried searching the SO, but all results I've found seem to deal with updating PK of entities that have already been persisted to the DB. My case is different.
I have 3 tables in a database with 1-0..1 relationships. The relationships look like this:
A <- B <- C
where '<-' represents a relationship and points to the principal end. I.e. each B always has a related A, but an A can have no B. In other words, A's cardinality is 1 and B's is 0..1.
Each relationship is represented by a FK that goes from the child entity's PK to the parent entity's PK. Each PK is a uniqueidentifier Id column with client-generated value. I've generated an EF 4 model from the database which has the same relationships with same cardinality.
I'm trying to add child entites B and C to an existing A entity. For design reasons the couple of new instances is created in one peace of code, and the A entity is linked to the B entity in another one. Furthermore, I don't want the latter one to know that C exists.
Here's how the B and C creation code looks like:
public B CreateB()
{
return new B
{
Id = Guid.NewGuid(),
C = new C(),
};
}
And now the link and save code:
// a is an instance of A that has been loaded from DB
// and hence has a persistent Id value.
// b is a just-created instance of B
// that has a non-persistent Id value and null reference to A.
void SaveBlahBlahBlah(A a, B b)
{
// At this point b and c have the same Id value.
// It differs from a's Id, but that's expected, they haven't been linked yet.
b.A = a;
// At this point b receives a's Id value, but c keeps the original one,
// therefore the existing b-c link gets broken!
using(var ctx = new MyContext())
{
ctx.As.Attach(a); // This throws exception saying
// I've violated referential integrity.
// It doesn't say which relationship is broken,
// but I guess it's the B-C one since
// the debugger shows them to have different values if PKs
ctx.Bs.AddObject(b);
ctx.SaveChanges();
}
}
I've tried this both with the default EF's code generator (the one that uses EF's Entity class as base class for generated entities) and with the Self-Tracking Entities code generator. The result is the same.
So, the code crashes. The reason is likely to be that after A and B have been linked, B and C get different PK values which is illegal for entities with 1-1 relationship.
What I expected was C to automatically get it's PK synchronized to the value B got from A instance. That seems reasonable because I work with an object graph, I have an existing B-C relation which is OK and I expect it to remain OK after linking B with A. Why would it break? I would understand it if either B or C existed in DB and I wasn't able to change their PKs. But it's not the case, both entites have been just created.
I cannot break the chain of keys by using separate from PKs columns for FKs because EF requires both sides of a 1-1 relationship to be the PKs.
I don't want to sync keys manually because in fact there are more 1-1 related tables and that would require the sync code to appear in many places.
I believe I will be able to update the T4 template of the STE generator to cascade PK updates down 1-1 relationships. But I'm not too familiar with T4 and not too happy to do that.
I have 2 questions:
Is my expectation of cascaded PK updates in my case wrong for some reasons? (Seems bizarre though) I.e., is it a bug or a feature?
Are there any other and preferably simpler ways to fix the issue than modifying the STE template? Maybe some magic options in EF mappings or context?
Thanks in advance.
The problem is that the service which handles the assignment of IDs from one referenced object to another is the context. But at the time when you actually make the association, neither object is in the context. That wouldn't normally be a problem because the relationship will be fixed up when you add B to the context.
Unfortunately, you don't do this. Instead, you create an additional relationship with A, but then lie to the context and claim that everything is already fixed up. More precisely, you call EntitySet.Attach, which is really only intended for already fixed-up objects.
On the other hand, code like this should work just fine:
public B CreateB()
{
return new B
{
Id = Guid.NewGuid(),
C = new C(),
};
}
void SaveBlahBlahBlah(A a, B b)
{
using(var ctx = new MyContext())
{
ctx.Bs.AddObject(b);
ctx.SaveChanges();
}
}
Note that all I've done here is delete the problematic code, which has nothing to do with the relationship between B and C.
In short, beware of Attach. You need to know what you're doing when you call it.
UPDATE
A version that handles existing instances of A:
void SaveBlahBlahBlah(A a, B b)
{
Debug.Assert(a.B != b);
using(var ctx = new MyContext())
{
ctx.As.Attach(a);
a.B = b; // it's crucial that this link is set after attaching a to context!
ctx.Bs.AddObject(b);
ctx.SaveChanges();
}
}
I am just starting to use the Entity Framework 4 for the first time ever. So far I am liking it but I am a bit confused on how to correctly do inheritance.
I am doing a model-first approach, and I have my Person entity with two subtype entities, Employee and Client. EF is correctly using the table per type approach, however I can't seem to figure out how to determine what type of a Person a specific object is.
For example, if I do something like
var people = from p in entities.Person select p;
return people.ToList<Person>();
In my list that I form from this, all I care about is the Id field so i don't want to actually query all the subtype tables (this is a webpage list with links, so all I need is the name and the Id, all in the Persons table).
However, I want to form different lists using this one query, one for each type of person (so one list for Clients and another for Employees).
The issue is if I have a Person entity, I can't see any way to determine if that entity is a Client or an Employee without querying the Client or Employee tables directly. How can I easily determine the subtype of an entity without performing a bunch of additional database queries?
Use .OfType<Client>() in your query to get just the clients. See OfType.
e.g. entities.Person.OfType<Client>() ...
Use is to test if a Person object is a specific sub-class, e.g. if (p is Employee) ...
BTW why isn't it entities.People? Did you not select the pluralization option?