Entity object : Cloning and Inserting - database

I am trying to clone/copy an entity object and insert it to the DB. I am using Entity Framework.
I found several similar question here and over other forums. Though the exact issue, None of the solution worked for me.
Application orginalApp = new Application().GetById(origAppId);
Application clonedApp = orginalApp.Clone<Application>(); //uses DataContractSerializer
DataBaseContext.Current.Detach(orginalApp); // Current is a property which returns Database context which is stored in httpcontext.current.items
clonedApp.EntityKey = null; // tried with and without this
clonedApp.Application_Id = 0; // tried with and without this. This is the primary key
clonedApp.Application_Name += " (clone)";
clonedApp.Create(); //The usual Addobject and SaveChange()
This throws the following error:
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
I tried to check for existance of the object in object state manager.
DataBaseContext.Current.ObjectStateManager.GetObjectStateEntry(clonedApp)
It give me Null.
* Though, I couldnt find a solution, got to a workaround for the requirement using reflection.*

This error says that you have the same primary key for your new object as you did for your old one, if you are cloning rows, you will need a new PK for the cloned row

Related

Appengine entity update not working

I am developing code for app engine. I tried to update an existing row by updating the same entity returned as result of query. But it creates new row instead of updating the same row. Following is the code:
public boolean updateProfile(DbProfile profile) {
Transaction txn = _datastore.beginTransaction();
Entity entity = getProfileEntity(profile.getLoginId());
if (entity != null) {
entity.setProperty(DbProfile.DbProfilePropertyNames.address, profile.getAddress());
entity.setProperty(DbProfile.DbProfilePropertyNames.name, profile.getName());
Key key = _datastore.put(entity);
txn.commit();
return true;
}
return false;
}
private Entity getProfileEntity(String userName) {
Key eRecommendationKey = KeyFactory.createKey("eRecommendation", _dbKeyName);
FilterPredicate predicateUsername =
new FilterPredicate(DbProfile.DbProfilePropertyNames.loginId, FilterOperator.EQUAL,
userName.toUpperCase());
Query query =
new Query(DbProfile.entityProfileName, eRecommendationKey).setFilter(predicateUsername);
List<Entity> profiles =
_datastore.prepare(query).asList(FetchOptions.Builder.withDefaults());
Utils.log.log( Level.SEVERE, "not found"+profiles.size() );
if (profiles.size() == 0) {
//profile data is not set yet
return null;
} else {
return profiles.get(0);
}
}
Following image shows fields in the entity.
Please let me know how can I fix the issue.
My Java skills are not too good, so I find it difficult to understand your code sample. I also don't see where updateProfile() is called and how your code is getting or constructing the profile object, especially whether the key of the profile object is altered.
But in general, if new entities are created instead of updating existing entities, the reason is that the key at your updating commit is different from the actual key of the existing entity.
Typical situations:
a string (key-name) is used instead of an integer (ID), or vice versa
a typo in the kind name of the key
different namespace or app properties of the key
parents are missing in the key path or are constructed wrongly
Suggestion:
In datastore viewer, compare the key of an existing entity with the key of the accidentally created entity. The difference between both keys might give you a hint where to look in your code for the bug.
I solved the problem. It was my mistake. I had called saveData servlet instead of updateProfile servlet.

primary key constraint updating many-to-many self referential table in entity framework code-first

TL;DR What is the proper way of rehydrating an entity framework object with a self referential many to many relationship from a DTO and updating it with the new values so that the database updates correctly?
I have the following entity (irrelevant stuff trimmed)
public class Role
{
[Key]
[Required]
public String RoleId { get; set; }
public List<Role> Children { get; set; }
}
In my dbContext, I have set up a many to many relationship
modelBuilder.Entity<Role>().HasMany(r => r.Children).WithMany();
I'm using MVC front end, with a web-api backend for an n-tier setup, and an mssql database.
The following chain of events happens
Browser->MVC Controller->REST call to Web API->WebAPI Controller->DB Context Query
This chain happens twice, once to view the page in edit mode, and then again when the user pushes the save button to persist.
When setting children on the entity, they always already exist first (IE, you don't create the parent and the children at the same time, you are just adding an existing child to a parent)
There is a DTO used by the MVC model and web API, which I re-hydrate to the entity on the web-api side.
public IHttpActionResult UpdateRoleInfo(RoleVM roleInfo){
//lookup existing entity to update
var existing = db.Roles.FirstOrDefault(y => y.RoleId == roleInfo.ExistingRoleId);
...Something happens here (see below for things i've tried)...
db.SaveChanges();
}
My first try was this :
existing.Children = roleInfo.Children
This tried to recreate all of the existing children as part of the save. (Primary key constraint violation on the roles table)
I changed that to
//Fetch all of the roles from the database to lookup the existing children
var allRoles = GetRoles();
//Have to reselect the roles from the DB so the DB doesn't try to recreate new ones for the children.
var childrenToAdd = roleInfo.Roles.Select(role2 => allRoles.FirstOrDefault(r => r.RoleId == role2.RoleId)).ToList();
existing.Children = childrenToAdd;
This correctly works for updating a role that does not already have any children, to add some the first time, but if you update a role that already has children, it tries to re-add the children to the database a second time, getting a primary key violation on the roles_role table
I then tried pre-pending this code to the second one above,
existing.Children.Clear();
db.SaveChanges();
I would expect this to delete all the existing parent-child relationships from the many to many table for this parent, and then recreate them with the new children. Why not?
TL;DR What is the proper way of rehydrating an entity framework object with a self referential many to many relationship from a DTO and updating it with the new values so that the database updates correctly?
Try turning off auto detect changes (before retrieving from the DB) via
context.Configuration.AutoDetectChangesEnabled = false;
Then set the state to modified on the specific role object you are updating
context.Entry(role).State = EntityState.Modified;
Haven't tried this myself on a self-referencing many-to-many table, but adding & updating entities in the manner can save all sorts of headaches where EF incorrectly infers what you are adding/updating
Found the problem.
On the initial load of the entity, I was using an include statement to eager load the children.
When I updated the entity, when I fetched it from the db again, I did not eager load the children. Therefore the additions/updates were getting confused. Once I put the include in during the upload Scenario #2 above worked (the explicit clear was not needed)
db.Roles.Include("Children").FirstOrDefault(z => z.RoleId == RoleId);
Also related, if you have this same problem when dealing with relationships across different tables, make sure all the entities that are involved in the graph are from the same DB context!
https://msdn.microsoft.com/en-us/magazine/dn166926.aspx

Error in saving related objects in Entity Framework

I have a structure like this
DRDLines:
ID
DrawingRevisionID
DrawingRevision:
ID
Name
They're related in a one-to-many relationship.
In this code example
DRDLine line;
using (var db = new AMPX_DCEntities())
{
line = db.DRDLines.Single(p => p.ID == 1);
System.Console.WriteLine(line.DrawingRevision.ID);
}
using (var db = new AMPX_DCEntities())
{
var id = 12;
line.DrawingRevisionID = id;
}
using (var db = new AMPX_DCEntities())
{
db.Entry(line).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
}
I get this error
A referential integrity constraint violation occurred: The property value(s) of 'DrawingRevision.ID' on one end of a relationship do not match the property value(s) of 'DRDLine.DrawingRevisionID' on the other end.
What I've found: it doesn't update relations in DRDLines inside DrawingRevision
Debugging I see:
line.DrawingRevision.DRDLines[0].ID != line.DrawingRevisionID
If I remove line
System.Console.WriteLine(line.DrawingRevision.ID);
or write it like this
System.Console.WriteLine(line.DrawingRevisionID);
everything goes without errors. But I need that line to be used.
So, how can I fix that?
My guess is that the problem is caused by repeatedly creating a new context and then disposing it. When you set the DrawingRevisionID here
using (var db = new AMPX_DCEntities())
{
var id = 12;
line.DrawingRevisionID = id;
}
line is detached from the dbcontext from which it was retreived, but isn't attached to the new DbContext you've created, hence EF won't wire up the relationships when you change the ID.
You could attach the line object back to the context before changing the ID
db.DRDLines.Attach(line);
That will change both the IDs (although you could just change the other ID manually). Since that context is then disposed, you may need to set the EntityState to Modified for the DrawingRevision (or at least of the ID property) in the last DbContext session.
Also, I would add an Include to the original query to eagerly load the DrawingRevision. At the moment its only loaded when you query the ID on the System.Console line, hence why the behaviour is different. This also causes an extra trip to the database. Putting it into an include will be more efficient and more predictable.

JPA map entity with array datatype

I have a table which contains a column of type: integer[]
I'm trying to map my entity to this table and I've tried the following suggestion of:
#ElementCollection
private ArrayList<Integer> col;
public MyEntity() {
col = new ArrayList<>();
}
However I get the following error: Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements
Not sure how to get around this. I'm open to changing the entity's datatype, but I would prefer not to move this property into its own table/entity. Is there another solution? Thanks.
The field must be of type List<Integer>, not ArrayList<Integer>.
The JPA engine must be able to use its own List implementation, used for lazy-loading, dirty checking, etc.
It's a good idea in general to program on interfaces rather than implementations, and it's a requirement to do it in JPA entities.

GAE get Data using JDO with key

I created Key with my unicue ID, and save into the database.
GoogleDrivePDF pdf = new GoogleDrivePDF();
key= KeyFactory.createKey(GoogleDrivePDF.class.getSimpleName(),"0B1IQEoiXFg3IWHhJNEtlMzlvQWs");
pdf.setKey(key);
pdf.setPdfName("NAME");
everything works!
But know I have one problem.
In order to get my Object From Db I must need Key string.
GoogleDrivePDF pdf = pm.getObjectById(GoogleDrivePDF.class, "agtsdHYtY2hlY2tlcnJoCxIRVXNlcnNQREZEb2N1bWVudHMiIXZha2h0YW5nLmtvcm9naGxpc2h2aWxpQGdtYWlsLmNvbQwLEg5Hb29nbGVEcml2ZVBERiIcMEIxSVFFb2lYRmczSVdIaEpORXRsTXpsdlFXcww");
how to create that key? I think it is enycrypted key. How can I now get this object?
P.S I think because of I have one to many relationship, that may does not work. Because When I create that pdf without 1:N it gets object very well. But I cant get another datas, which are in 1:N
I have that error:
Could not retrieve entity of kind GoogleDrivePDF with key GoogleDrivePDF("0ByMb_8ccYJRFOS1ibmFtamZ1b2M")
org.datanucleus.exceptions.NucleusObjectNotFoundException: Could not retrieve entity of kind GoogleDrivePDF with key GoogleDrivePDF("0ByMb_8ccYJRFOS1ibmFtamZ1b2M")
If you want to create a Key based on some other field of your Entity (say, for instance, a field called uniqueID), you should do something like this:
Persisting:
GoogleDrivePDF pdf = new GoogleDrivePDF();
pdf.setUniqueID("0B1IQEoiXFg3IWHhJNEtlMzlvQWs");
Key key = KeyFactory.createKey(GoogleDrivePDF.class.getSimpleName(),pdf.getUniqueID());
pdf.setKey(key);
pm.makePersistent(pdf);
BTW, it is generally not a good choice to make the key field publicly accessible. I think it is better to put the code for the creation of the key inside a specific constructor, like
public GoogleDrivePDF(String uniqueID) {
this.setUniqueID(uniqueID);
this.key = KeyFactory.createKey(GoogleDrivePDF.class.getSimpleName(),uniqueID);
}
Retrieving:
String idToBeRetrieved = "0B1IQEoiXFg3IWHhJNEtlMzlvQWs";
Key key = KeyFactory.createKey(GoogleDrivePDF.class.getSimpleName(),idToBeRetrieved);
pm.getObjectById(GoogleDrivePDF.class, key);
Solution was Unowned:
#Unowned
#Persistent
private Map <String,GoogleDrivePDF > pdfs;

Resources