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.
Related
I want to ensure that only one entity is created for an entity with a specific ancestor Key. My solution is to put the ancestor query inside a transaction, check if the entity exists, and if not, create it.
Will this ensure only one entity exists with a specific ancestor key?
ofy().transact(new VoidWork() {
public void vrun() {
Entity entity = ofy().load().type(Entity.class)
.ancestor(ancestorKey)
.first()
.now();
if (entity == null) {
// Entity does not exist. Create it.
final Entity newEntity = new Entity(ancestorKey);
ofy().save().entity(newEntity).now();
} else {
// Entity already exists.
}
}
}
});
SO doesn't like one-word answers so I can't just say "Yes".
If you're just trying to ensure that one and only one thing exists, you don't need the ancestor query - just do a get-by-key on a known id.
And since Java7 is gone, no reason not to put this in a lambda.
I have the following problem: when i try to change the town of a user by passing the modified user entry to my ModifyUser method in my UserService class everything seems ok but the changes are not applied in the database.
I tried the solutions from similar problems i found on stackoverflow but none of them seem to work.
As they say "a picture is worth a thousand words" take a look at this, since its easier to understand compared to my short explanation.
http://prntscr.com/el51z0
else if (property == "BornTown")
{
if (this.townService.TownExists(value))
{
User user = this.userService.GetUserByName(username);
Town town = this.townService.GetTownByName(value);
user.BornTown = town;
this.userService.ModifyUser(user);
}
else
{
Console.WriteLine($"Value {value} is not valid.");
throw new ArgumentException($"Town {value} not found!");
}
}
When i pass the user to the ModifyUser the database does not update, and BornTown stays NULL.
public void ModifyUser(User user)
{
using (PhotoShareContext context = new PhotoShareContext())
{
context.Users.Attach(user);
context.Entry(user).State = EntityState.Modified;
context.SaveChanges();
}
}
Or else try below code:
User user = context.users.where(x=>x.username == username).FirstOrDefault();
user.BornTown = town; //string
context.savechanges();
Can you try
context.Users.where(x=>x.username == username).FirstOrDefault();
and don't use any()
Can you check if you are getting the proper username, by again checking the username once you are getting back the value in the function.
Instead of manipulating the navigation properties directly try to manage the entity relation using it's foreign keys:
Town town = this.townService.GetTownByName(value);
user.BornTownId = town.Id;
Keep in mind that if you have not created explicit foreign keys in your model entity you should map the existing one: take a look at "Users" table - see how the foreign key column is named- it should look something like UserTown_Id. Then put it in your model class (you may add foreign key attribute or map it in model builder).
Be careful when adding the new property to your model (it can make your optional relation with "Towns" required).
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
I'm currently developing a mobile application who uses a Google App Engine-hosted web service.
But i'm facing an issue. I just want to add a field in one my database's table.
App Engine doesn't use classic SQL syntax, but GQL. So i cannot use the ALTER TABLE statement. How can i do this with GQL ? I looked for a solution on the web, but there's not a lot of help.
public MyEntity() {
}
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Key idStation;
private String name;
private double longitude;
private double latitude;
private java.util.Date dateRefresh = new Date(); //the field i want to add in DB
So, now when i create a "MyEntity" object, it should add the "dateRefresh" field into the database... I create my object like this:
MyEntity station = new MyEntity();
station.setName("test");
station.setLatitude(0);
station.setLongitude(0);
station.setDateRefresh(new Date("01/01/1980"));
DaoFactory.getStationDao().addStation(station);
addStation method:
#Override
public MyEntity addStation(MyEntity station) {
EntityManager em = PersistenceManager.getEntityManagerFactory().createEntityManager();
try {
em.getTransaction().begin();
em.persist(station);
em.getTransaction().commit();
} finally {
if(em.getTransaction().isActive()) em.getTransaction().rollback();
em.close();
}
return station;
}
The field "dateRefresh" is never created into my DB...
Someone to help me please ?
Thanks in advance
Just add another field to your data structure, maybe providing a default clause, and that's all. For example, if you have a UserAccount:
class UserAccount(db.Model):
user = db.UserProperty()
user_id = db.StringProperty()
you may easily add:
class UserAccount(db.Model):
user = db.UserProperty()
user_id = db.StringProperty()
extra_info = db.IntegerProperty(default=0)
timezone = db.StringProperty(default="UTC")
and let it go.
While the datastore kinda mimics tables, data is stored on a per entity basis. There is no schema or table.
All you need to do is update your model class, and new entities will be saved with the structure (fields) of the new entity.
Old entities and indexes, however, are not automatically updated. They still have the same fields as they had when they were originally written to the datastore.
There's two ways to do this. One is to make sure your code can handle situations where your new properties are missing, ie make sure no exceptions are thrown, or handle the exceptions properly when you're missing the properties.
The second way is to write a little function (usu a mapreduce function) to update every entity with appropriate or null values for your new properties.
Note that indexes are not updated unless the entity is written. So if you add a new indexed property, old entities won't show up when you query for the new property. In this case, you must use the second method and update all the entities in the datastore so that they are indexed.
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