I am writing this out of my head now, so correct me if I'm wrong. But I think to remember that the following code verifies if the entity behind a Ref<> actually exists:
Ref<User> user; // we have a reference field to a user in another entity
public void referenceUser(Long userId) {
Key<User> key = Key.create(User.class, userId); // this is protobuf as it looks, and no db access happens
this.user = Ref.create(key); // this looks up if an existing record exists, and it fails if it does not, correct?
}
What happens if the Ref<> field is already set during an update? Is it correct that it is not verified again if the record still exists?
I would like to clarify when objectify ensures data integrity and when it does not cross-check if a referenced record exists.
Objectify never ensures any kind of referential integrity. Neither does the low-level API.
Ref objects are just Key objects with a little more behavior (most importantly the get() method).
Related
I have the User entity that contains the Email/Name/.../HashedPassword/Salt.
Now, every time, after the user logs in the entire User entity goes to the client so that the user can modify some of the properties.
However I would prefer not to send the last two properties; but if I set them to null before send them to client, then when the entity comes back, I would need to get the original entity from the database, set the two properties to the just arrived entity then save it.
Is there a better solution, like saving only a part of the entity?
Or maybe I am security paranoid and this is not a problem.
For avoiding reading, you can just select a new object without the properties you do not want to expose:
return user.Select(x => new User
{
Id = x.Id,
Email = x.Email,
Name = x.Name,
});
Your update procedure is the correct way to handle this.
I have several entities, each with its form type. I want to be able, instead of saving the entity straight away on save, to save a copy of the changes we want to perform and store it in DB.
We'd send a message to the user who can approve the change, who will review the original and the changed field(s) and will approve or not. If approved the entity would be properly flushed.
To solve the issue I was thinking about:
1) doing a persist
2) getting the changesets (both the one related to "normal" fields, and the one relative to collections)
3) storing it in DB
4) Performing $em->refresh() to discard changes.
Later what I need is to get the changset(s) back, ask the (other) user to approve it and flush it.
Is this doable? What I'm especially concerned about is that the entity manager that generated the first changeset is not the same we are going to use to perform the flush, I basically need to "load" a changeset.
Any idea on how to solve the issue (this way, or another way ;) )
Another solution (working only for "normal" fields, not reference ones that come from other entities to the current one, like a many to many) would be to clone the current entity, store it, and then once approved copy the field(s) from the cloned to the original one. But it does not work for all fields (if the previous solution does not work we'd limit the feature just to "normal" fields).
Thank you!
SN
Well, you could just treat the modifications as entities themselves, so that every change is stored in the database, and then all the changes that were approved are executed against the entity.
So, for example, if you have some Books stored in the database, and you want to make sure that all the modifications made to these are approved, just add a model that would contain the changeset that has to be processed, and a handler that would apply these changes:
<?php
class UpdateBookCommand
{
// If you'll store these commands in a database, perhaps this field would be a relation,
// or you could just store the ID
public $bookId;
public $newTitle;
public $newAuthor;
// Perhaps this field should be somehow protected from unauthorized changes
public $isApproved;
}
class UpdateBookHandler
{
private $bookRepository;
private $em;
public function handle(UpdateBookCommand $command)
{
if (!$command->isApproved) {
throw new NotAuthorizedException();
}
$book = $this->bookRepository->find($command->bookId);
$book->setTitle($command->newTitle);
$book->setAuthor($command->newAuthor);
$this->em->persist($book);
$this->em->flush();
}
}
Next, in your controller you would just have to make sure that the commands are somehow stored (in a database or maybe even in a message queue), and the handler gets called when the changesets could possibly get applied.
P.S. Perhaps I could have explained this a bit better, but mostly the inspiration for this solution comes from the CQRS pattern that's explained quite well by Martin Fowler. However, I guess in your case a full-blown CQRS implementation is unnecessary and a simpler solution should work.
I've got a WebAPI OData controller which is using the Delta to do partial updates of my entity.
In my entity framework model I've got a Version field. This is a rowversion in the SQL Server database and is mapped to a byte array in Entity Framework with its concurrency mode set to Fixed (it's using database first).
I'm using fiddler to send back a partial update using a stale value for the Version field. I load the current record from my context and then I patch my changed fields over the top which changes the values in the Version column without throwing an error and then when I save changes on my context everything is saved without error. Obviously this is expected, the entity which is being saved has not been detacched from the context so how can I implement optimistic concurrency with a Delta.
I'm using the very latest versions of everything (or was just before christmas) so Entity Framework 6.0.1 and OData 5.6.0
public IHttpActionResult Put([FromODataUri]int key, [FromBody]Delta<Job> delta)
{
using (var tran = new TransactionScope())
{
Job j = this._context.Jobs.SingleOrDefault(x => x.JobId == key);
delta.Patch(j);
this._context.SaveChanges();
tran.Complete();
return Ok(j);
}
}
Thanks
I've just come across this too using Entity Framework 6 and Web API 2 OData controllers.
The EF DbContext seems to use the original value of the timestamp obtained when the entity was loaded at the start of the PUT/PATCH methods for the concurrency check when the subsequent update takes place.
Updating the current value of the timestamp to a value different to that in the database before saving changes does not result in a concurrency error.
I've found you can "fix" this behaviour by forcing the original value of the timestamp to be that of the current in the context.
For example, you can do this by overriding SaveChanges on the context, e.g.:
public partial class DataContext
{
public override int SaveChanges()
{
foreach (DbEntityEntry<Job> entry in ChangeTracker.Entries<Job>().Where(u => u.State == EntityState.Modified))
entry.Property("Timestamp").OriginalValue = entry.Property("Timestamp").CurrentValue;
return base.SaveChanges();
}
}
(Assuming the concurrency column is named "Timestamp" and the concurrency mode for this column is set to "Fixed" in the EDMX)
A further improvement to this would be to write and apply a custom interface to all your models requiring this fix and just replace "Job" with the interface in the code above.
Feedback from Rowan in the Entity Framework Team (4th August 2015):
This is by design. In some cases it is perfectly valid to update a
concurrency token, in which case we need the current value to hold the
value it should be set to and the original value to contain the value
we should check against. For example, you could configure
Person.LastName as a concurrency token. This is one of the downsides
of the "query and update" pattern being used in this action.
The logic
you added to set the correct original value is the right approach to
use in this scenario.
When you're posting the data to server, you need to send RowVersion field as well. If you're testing it with fiddler, get the latest RowVersion value from your database and add the value to your Request Body.
Should be something like;
RowVersion: "AAAAAAAAB9E="
If it's a web page, while you're loading the data from the server, again get RowVersion field from server, keep it in a hidden field and send it back to server along with the other changes.
Basically, when you call PATCH method, RowField needs to be in your patch object.
Then update your code like this;
Job j = this._context.Jobs.SingleOrDefault(x => x.JobId == key);
// Concurrency check
if (!j.RowVersion.SequenceEqual(patch.GetEntity().RowVersion))
{
return Conflict();
}
this._context.Entry(entity).State = EntityState.Modified; // Probably you need this line as well?
this._context.SaveChanges();
Simple, the way you always do it with Entity Framework: you add a Timestamp field and put that field's Concurrency Mode to Fixed. That makes sure EF knows this timestamp field is not part of any queries but is used to determine versioning.
See also http://blogs.msdn.com/b/alexj/archive/2009/05/20/tip-19-how-to-use-optimistic-concurrency-in-the-entity-framework.aspx
I'm making a survey program that has a list of questions that are pulled from the database as entities. During the course of the survey the properties of the entity may be edited, but I do not want these changes persisted to the database. So, I detach the questions after they are loaded into the dbcontext and access them via a dictionary.
The problem arises when I attempt to save an answer to the database. Since the answer entity is related to the question entity (that has been detached) a completely new question entity is then added to the database. I'm not sure why this is occurring as the answer entity being added contains the proper ID of the detached entity (when I look at it in the debugger). However, upon saving changes it gets updated to the ID of the newly created duplicate entity.
Is there a way to stop this behavior? Or alternatively, is there a way to make changes to an entity and not have them persist to the database even when SaveChanges is called on the context for writing a answer or a log entry to the database?
Here is the code that loads, then detatches the questions (items):
public FixedLengthBlockElementRuntime(FixedLengthBlock block, RuntimeContext context) : base(block, context)
{
this._items = ((FixedLengthBlock)this.Element).ItemBank.Items.OfType<FixedLengthItem>().ToDictionary(x => x.ItemName, x => x);
foreach(FixedLengthItem fixedLengthItem in this._items.Values)
{
this.Context.DetachEntity(fixedLengthItem);
}
}
And here is the code that adds the duplicate entry:
public void SetResponse(Response response)
{
response.Session = this.Session;
this.DbContext.Responses.AddObject(response);
this.DbContext.SaveChanges();
}
Note that Response has the proper ItemId until the point of Saving Changes.
You can set the MergeOption on your questions DbSet to be OverwriteChanges.
Context.Questions.MergeOption = MergeOption.OverwriteChanges;
You'll need to be sure you set that BEFORE you make the query for the questions for this to work properly however.
More reading on how MergeOptions work
I'm trying to query UserMetaData for a single record using the following query
using (JonTestDataEntities context = new JonTestDataEntities())
{
return context.UserMetaData.Single(user => user.User.ID == id);
}
The error I'm receiving is: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection. It is trying to lazyload Group for UserMetaData record. How can I change my query to prevent this error?
As the message says, you cannot lazily load it after the function returns, because you've already disposed the context. If you want to be able to access Group, you can make sure you fetch it earlier. The extension method .Include(entity => entity.NavigationProperty) is how you can express this:
using (JonTestDataEntities context = new JonTestDataEntities())
{
return context.UserMetaData.Include(user => user.Group).Single(user => user.User.ID == id);
}
Also consider adding .AsNoTracking(), since your context will be gone anyway.
You need to create a strong type that matches the signature of your result set. Entity Framework is creating an anonymous type and the anonymous type is disposed after the using statement goes out of scope.
So assigning to a strong type avoids the issue altogether. I'd recommend creating a class called UserDTO since you're really creating a data transfer object in this case. The benefit of the dedicated DTO is you can include only the necessary properties to keep your response as lightweight as possible.