Lets say a Blog class with Comment Object as reference.
Comment Object has Id, Comment Date, Comment. (Reference) NOT EMBEDDED.
How do I remove a comment?
Assuming a blog post entity can have multiple comments, but each comment belongs to exactly one blog post.
First you'll need to remove the reference:
BlogPostEntity blog = mongoDataStore.find(BlogEntity.class)
.field("comments")
.hasThisElement(new Key<CommentEntity>(CommentEntity.class, comment.getId()))
.get();
if (blog != null) {
blog.removeComment(comment); // Assuming you have a remove method for that, otherwise use the setter
persist(blog); // Assuming you have a generic persist method
}
Then you can remove the entity itself:
mongoDataStore.delete(comment);
Related
I'm a little fuzzy on how the delete rules for relationships in Core Data work, at least beyond the simple cases described in the documentation.
Most of those cases, and most of the answers I've seen for questions here, use a model where the object on left side of a one-to-many relationship "owns" the objects on the right side: e.g. a Person has PhoneNumbers, and if you delete the person you delete all their associated numbers. In that kind of case, the solution is clear: Core Data will handle everything for you if you set the relationships like so:
Person --(cascade)-->> PhoneNumber
PhoneNumber --(nullify)--> Person
What I'm interested in is the opposite: A to-many relationship where the "ownership" is reversed. For example, I might extend the CoreDataBooks sample code to add an Author entity for collecting all info about a unique author in one place. A Book has one author, but an author has many books... but we don't care about authors for whom we don't list books. Thus, deleting an Author whose books relationship is non-empty should not be allowed, and deleting the last Book referencing a particular Author should delete that Author.
I can imagine a couple of ways to do this manually... what I'm not sure of is:
does Core Data have a way to do at least some of this automagically, as with relationship delete rules?
is there a "canonical", preferred way to handle this kind of situation?
You could override prepareForDeletion in your Book class and check if the author has any other books. If not you could delete the author.
- (void)prepareForDeletion {
Author *author = self.author;
if (author.books.count == 1) { // only the book itself
[self.managedObjectContext deleteObject:author];
}
}
Edit: To prevent deletion of an author with books you could override validateForDelete or even better: don't call deleteObject with an author with books in the first place
Rickstr,
Check below for the relationships to get your two criteria done.
Author -- (Deny) -->> Books
deleting an Author whose books relationship is non-empty should not be allowed
DENY: If there is at least one object at the relationship destination, then the source object cannot be deleted.
Book -- (Cascade)-- > Author
deleting the last Book referencing a particular Author should delete that Author
You cannot delete the Author, as our first rule is saying, if there are any Books which are non-empty should not be deleted. If they are not present the Author gets deleted.
I think theoretically it should work. Let me know, if this works or not.
Similarly to Tim's solution, you can override the willSave method in your Author NSManagedObject subclass. Note that if you do use Tim's solution, I highly recommend filtering the books set for books that haven't been deleted; this way if you delete all of the Author's books at the same time, the Author will still be deleted.
- (void)willSave {
if (!self.isDeleted) {
NSPredicate *notDeletedPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary<NSString *,id> *bindings) {
return ![(NSManagedObject *)evaluatedObject isDeleted];
}];
NSSet *filteredBooks = [self.books filteredSetUsingPredicate:notDeletedPredicate];
if (filteredBooks.count == 0)
[self.managedObjectContext deleteObject:self];
}
[super willSave];
}
The following worked for me:
Set the deletion rule on the 'book' relationship of your author entity to 'Deny' meaning that as long as there is a book linked to your author it cannot be deleted.
Subclass your book entity and override the prepareForDeletion() function as follows:
public override func prepareForDeletion() {
super.prepareForDeletion()
do {
try author.validateForDelete()
managedObjectContext?.delete(author)
} catch {}
}
Validate for delete will throw an error unless the book relationship is empty.
You can optionally handle the error.
I use LinqToEntitiesDomainService class to update database with Silverlight 4 client.
There's AttachAsModified extended method for entity framework ObjectContext which allows you supply original entity property values:
Order original = this.ChangeSet.GetOriginal(currentOrder);
this.ObjectContext.Orders.AttachAsModified(currentOrder, original);
By default, WCF RIA Services doesn't send original values to the server, so one needs to
apply [RoundtripOriginal()] attribute to his/her entity.
However, even if I supply original values, SQL generated by Entity framework updates all columns, not only changed ones. Since AttachAsModified() method isn't native ObjectContext class method (it's extended method defined in ObjectContextExtensions class), I tried to use
ApplyOriginalValues method which is defined in ObjectSet class. No change.
It seems entity framework 4.1, which was released recently may have solution (not sure). How about entity framework 4? Is it possible EF to generate sql to update only changed columns?
AttachAsModified will mark the entity as modified. Subsequently (quote from MSDN):
When you change the EntityState of an
entity object entry to Modified, all
of the properties of the object are
marked as modified, regardless of the
current or original values.
Caveat; I haven't done this but, it should work.
Instead of using AttachAsModified, mark the entity as UnChanged using the ChangeState method.
Then use the SetModifiedProperty method on the properties that have changed to have them included in an update.
EDIT: If you want a way to find which properties have changed, there are a couple of articles out there explaining how to do so using the ObjectStateManager such as this one
I did ask similar question on MSDN forums, and it is confirmed that WCF RIA Services will change all columns. Alternative is,
You can fetch a copy from database, compare and mark SetModifiedProperty manually by using reflection.
// change state of entity as Unmodified/Unchanged...
original.EntityState = Unchanged;
// this is copy form database...
// Use different context
MyOrderContext context = new MyOrderContext();
Order dbOriginal = context.Orders.First( x=>x.OrderID == original.OrderID);
foreach(PropertyInfo p in copy.GetTypes().GetProperties()){
Object originalValue = p.GetValue(dbOriginal);
Object newValue = p.GetValue(original);
if(originalValue!=null && newValue!=null
&& originalValue.Equals(newValue)){
continue;
}
// resetting this will
// make entity's only current
// property as changed
p.SetValue(original,originalValue);
p.SetValue(original,newValue);
}
You may have to change code as per situation, check if property is readonly or not and this is just a sample but it will help you to build upon it.
I managed to do this by first attaching the object and then calling ApplyOriginalValues on the EntitySet. You'll need an object with the original values to do this. This method can also be used to prevent a column from being updated, e.g. for row level security.
NOTE: This unfortunately does not work without retrieving the original entity from the database first. Otherwise only properties that are set to its default value are excluded from the update...
If I call Save on a new object, then populate its properties, NHibernate generates and insert statement that contains only the default values for the properties. For example (session is an open ISession):
var homer = new Person();
session.Save(homer);
homer.Name = "Homer J. Simpson";
session.Flush();
I thought that calling Save would make homer persistent and that NH would track any changes and include them in the insert. Instead, it issues an insert with the name property parameter set to null. If I put the Save call after the assignment then it works. This object has a GUID id assigned by NH so it's not doing a premature insert to get an identity.
ETA I'm using session-per-request in an ASP.NET app and the pattern I want to follow is:
MyObject myObject;
if (id == null)
{
myObject = new MyObject();
repository.Add(myObject);
}
else
{
myObject = repository.GetMyObject(id);
}
// populate myObject's properties
// NH magic happens here when the HTTP request ends
I think your assumption in this case is simply incorrect.
Reading the code sample you provided, you could just as well expect NHibernate to insert the object, and then subsequently change the Name and then issue an Update. That, however, would assume that Flush implicitly saves the changed state.
I also wonder why this happens. NH should really wait to insert the object to the database.
Reasons why could do this:
the id, you already said that you are using guids, so this shouldn't be the reason.
there is a query. To ensure that it is performed on actual data, the session is flushed.
there are calculated columns, which need to be read back from the database
there might be other reasons I don't remember.
Is this really the code you are running to reproduce the test?
How does the mapping file look like?
You just mentioned it in the answer to my (perhaps rather naive) comment. You have set session FlushMode to Auto. Change that to Manual and you're more likely to see the behavior you are seeking.
It's still a rather wild guess, simply because so many other properties of your configuration can be at play.
What's a good name for a method that adds something to a container if it's not already there, i.e.
void AddCustomerToList(CustomerList list, Customer customer)
but that name does not properly convey that it won't be added if it's not there already. What is a better name? AddCustomerToListIfNotThereAlready? EnsureCustomerInList?
Change CustomerList to CustomerSet, then it's obvious.
add(CustomerSet set, Customer customer);
AddIfNotPresent
bool TryAdd(CustomerList list, Customer customer)
I would go with something like AddIfMissing, though I like the idea of renaming to Set since that's really what it is.
public static class ListExtensions
{
public static void AddIfMissing<T>( this List<T> list, T item )
{
if (!list.Contains(item))
{
list.Add( item );
}
}
}
Usually "put" would be used instead of "add" to convey this, but I agree with chase that you should just call this "add" and use "set" instead of "list". Unless of course the container supports both operations (which would be odd).
You could do like the generic list does and create a ContinsCustomer function to check if it exists first, then use AddCustomerToList if it returns false.
Make it two methods. IsCustomerPresent() AddCustomer(). Then if you want you could make a AddCustomerIfNotAlreadyPresent() method that just calls your loosely coupled logic.
in my opinion you are asking this question since you design OO is sub-optimal:
void AddCustomerToList(CustomerList list, Customer customer)
the responsability to ensure if a customer must be present must be assigned to
CustomerList.
In that case you name your method:
Add in the case you specify in the documentation that the customer will be added only if
not present
AddIfNotPresent or PutIfNotPresent otherwise.
I prefer the latter since it is more autodocumented.
Maybe just name it AddCustomerToList, and don't make it check to see if its already there, instead at the end, call another method, RemoveMultipleOccurences(..).
You didn't say what you do if it isn't there. Assuming the answer is "nothing", I'd go with.
bool InsertIfNew (CustomerList list, Customer customer)
The method returns true if it was "inserted", and false if it was already there. That the caller can perform alternate logic if the entry was already there. You might not want to do that, but someone might and you already have the knowledge inside the routine.
It seems that serializing Entity Framework objects into JSON is not possible using either WCF's native DataContractJsonSerializer or ASP.NET's native JavaScript serializer. This is due to the reference counting issues both serializers reject. I have also tried Json.NET, which also fails specifically on a Reference Counting issue.
Edit: Json.NET can now serialize and deserialize Entity Framework entities.
My objects are Entity Framework objects, which are overloaded to perform additional business functionality (eg. authentication, etc.) and I do not want to decorate these classes with platform-specific attributes, etc. as I want to present a platform-agnostic API.
I've actually blogged about the individual steps I went though at https://blog.programx.co.uk/2009/03/18/wcf-json-serialization-woes-and-a-solution/
Have I missed something obvious?
The way I do this is by projecting the data I want to serialize into an anonymous type and serializing that. This ensures that only the information I actually want in the JSON is serialized, and I don't inadvertently serialize something further down the object graph. It looks like this:
var records = from entity in context.Entities
select new
{
Prop1 = entity.Prop1,
Prop2 = entity.Prop2,
ChildProp = entity.Child.Prop
}
return Json(records);
I find anonymous types just about ideal for this. The JSON, obviously, doesn't care what type was used to produce it. And anonymous types give you complete flexibility as to what properties and structure you put into the JSON.
Microsoft made an error in the way they made EF objects into data contracts. They included the base classes, and the back links.
Your best bet will be to create equivalent Data Transfer Object classes for each of the entities you want to return. These would include only the data, not the behavior, and not the EF-specific parts of an entity. You would also create methods to translate to and from your DTO classes.
Your services would then return the Data Transfer Objects.
Based off of #Craig Stuntz answer and similar to a DTO, for my solution I have created a partial class of the model (in a separate file) and a return object method with how I want it using only the properties that will be needed.
namespace TestApplication.Models
{
public partial class Employee
{
public object ToObject()
{
return new
{
EmployeeID = EmployeeID,
Name = Name,
Username = Username,
Office = Office,
PhoneNumber = PhoneNumber,
EmailAddress = EmailAddress,
Title = Title,
Department = Department,
Manager = Manager
};
}
}
}
And then I call it simply in my return:
var employee = dbCtx.Employees.Where(x => x.Name == usersName).Single();
return employee.ToObject();
I think the accepted answer is more quick and easy, I just use my method to keep all of my returns consistent and DRY.
My solution was to simply remove the parent reference on my child entities.
So in my model, I selected the relationship and changed the Parent reference to be Internal rather than Public.
May not be an ideal solution for all, but worked for me.
One more solution if you want to have better code consistency is to use JavaScriptConverter which will handle circular reference dependencies and will not serialize such references.
I've blogged about here:
http://hellowebapps.com/2010-09-26/producing-json-from-entity-framework-4-0-generated-classes/
FYI I found an alternative solution
You can set the parent relationship as private so then the properties are not exposed during the translation removing the infinite property loop
I battled with this problem for days,
Solution. Inside your edmx window.
- right click and add code generation item
- Select Code tab
- select EF 4x.POCOC Entity Generator
If you don't see it, then you will have to install it with nuget, search EF.
The Entity generator will generate all you complex type and entity object into simple classes to serialize into json.
I solved it by getting only object types from System namespace, and then convert them to Dictionary and then add them to list. Works good for me :)
It looks complicated, but this was the only generic solution that worked for me...
I'm using this logic for a helper I'm making, so it's for a special use where I need to be able to intercept every object type in entity object, maybe someone could adapt it to his use.
List<Dictionary<string, string>> outputData = new List<Dictionary<string, string>>();
// convert all items to objects
var data = Data.ToArray().Cast<object>().ToArray();
// get info about objects; and get only those we need
// this will remove circular references and other stuff we don't need
PropertyInfo[] objInfos = data[0].GetType().GetProperties();
foreach (PropertyInfo info in objInfos) {
switch (info.PropertyType.Namespace)
{
// all types that are in "System" namespace should be OK
case "System":
propeties.Add(info.Name);
break;
}
}
Dictionary<string, string> rowsData = null;
foreach (object obj in data) {
rowsData = new Dictionary<string, string>();
Type objType = obj.GetType();
foreach (string propertyName in propeties)
{
//if You don't need to intercept every object type You could just call .ToString(), and remove other code
PropertyInfo info = objType.GetProperty(propertyName);
switch(info.PropertyType.FullName)
{
case "System.String":
var colData = info.GetValue(obj, null);
rowsData.Add(propertyName, colData != null ? colData.ToString() : String.Empty);
break;
//here You can add more variable types if you need so (like int and so on...)
}
}
outputData .Add(rowsData); // add a new row
}
"outputData " is safe for JSON encode...
Hope someone will find this solution helpful. It was fun writing it :)