CoreData: delete entity in many-to-many relationship - core-data

In my CoreData data model, there is a Note entity, and a Tag entity, they have many to many relationships, so each Note can have many Tags, and each Tag may belong to many Notes.
The tags are entered as strings separated by comma:
cat, dog, pig
then I split the string to 'cat', 'dog', 'pig'
suppose if I have a Note with tags 'cat', 'dog', 'pig', and I removed 'pig' and added 'bird', at first I have a string:
"cat, dog, bird" then 'cat', 'dog', 'bird',
Now what should I do? Should I remove all tags for this Note and re-add all the tags? But once I removed all the tags, do other Notes that share the same tag lose those tags?
Thanks!

You're confusing deleting an object with removing it from a relationship.
Firstly, check the delete rule on your relationship:
If the delete rule is "nullify", then that means that you can remove objects from the relationship without deleting the object. That sounds like what you want in this case: you want to be able to remove a tag from a relationship with a specific note without affecting all other notes that use the tag.
Regarding actually amending the relationship with your new set of tags, there are two things you could do. The first way is as you mentioned, to just remove all the tags from the note and re-add them. That's quite a good plan actually. When you're adding the tags, of course, for each tag you need to check if it exists first, and if it does, add the existing tag to the relationship.
In pseudocode:
Remove all the tags from your current note.
Make a mutable set, to hold the ones you want to add.
Get your new array of strings for the linked tags
For each tag string, do the following:
Create a predicate to find a Tag object with that name. Create a fetch request, and execute it.
Look at the result: if there is a returned tag (i.e. the result array has >0 objects in it), add that to your mutable set.
If there was no returned tag (i.e. there is no tag with that name), create a new Tag object. Add that to your mutable set.
Set your Note's tags property to your new set of tags.
The alternative way to do it, which lets you add and remove tags one at a time from the relationship, is to call NSMutableSet *mySet = [yourNote mutableSetValueForKey:#"tags"]. That returns you a mutable set of tag objects, and any changes you make to the set are automatically seen by Core Data. So you can remove an object from it, and then that object will no longer be in the relationship, or you can add another tag to the set, and it'll become related to the note.
At no time in any of this did we delete an object from the database. All your tags still exist, we just changed which ones are related to which notes.

Related

How to use <sw-entity-multi-select> correctly?

I am a bit confused how to use the component <sw-entity-multi-select>. I understand that the difference between this component and the <sw-entity-multi-id-select> is that the first one returns the entities and the latter one returns just the id of the selected entities. But from the structure and the props they are totally different.
I am confused, because I mainly use the component as this:
<sw-entity-multi-select
entityName="language"
:entity-collection="languages"
:criteria="salesChannelLanguageCriteria"
:label="Language"
#change="selectLanguage"
>
</sw-entity-multi-select>
I could remove the entityName here, as the name is retrieved from the collection as well. But when I dig into the core, I see that inside selectLanguage I should do this:
selectLanguage(languages) {
this.languageIds = languages.getIds();
this.languages = languages;
}
I now understand that languageIds are kind of the v-model that determine, which entities should be selected in the component. Is this true? Why do I have to set the this.languages here again then? To me it's kind of magic if languageIds have this role here, because it's not referenced anywhere on the component. How does it work and how do I tell the component which items are selected - is using languageIds the correct way?
I now understand that languageIds are kind of the v-model that determine, which entities should be selected in the component. Is this true?
No. This example probably just extracts the IDs for some other use, e.g. for adding associations of language to another entity. One could arguably that if this is the only purpose of the selection sw-entity-multi-id-select might be the better component to use.
Why do I have to set the this.languages here again then?
Because you want to store the updated entity collection to persist the selection. Whatever is selected within the multi select is derived from that collection. So, let's say, initially you start out with an empty entity collection. You select some entities and the change is emitted with the updated collection containing the selected entities. Given we have :entity-collection="languages" we then want this.languages to be this updated collection, so the selection persists. So we kinda complete a loop here.
On another note, you could also use the collection with v-model="languages". In that case any additions or removals within the selection would be applied reactively to the collection and you wouldn't need to set this.languages after each change and you could also remove :entity-collection="languages". So basically, which of these approaches you use depends on whether you want your changes applied reactively or not.

How to build complex value-object?

I just have started to learn DDD. So I apologise for silly question...
So I have the Post entity. It looks fine. But it should have tags.
In code it looks like this (ruby code):
class Post
attr_reader :tags
attr_reader :title
attr_reader :text
# ...
end
class Tag
attr_reader :name
attr_reader :description
# ...
end
Tags aren't make a sense as entity. I don't need tag itself.
But how should I to implement repository for post?
I have found 2 variants:
1.
Build tags in same repository. Like this:
# PostRepository
def find(id)
# getting post data from storage here
# getting tags data
Post.new(title, text, tags_data.map { |tag_data| Tag.new(tag_data[:name], tag_data[:description]))
end
But it looks ugly. Can't clearly say why.
2.
Make separate repository for tags.
# PostRepository
def find(id)
# getting post data from storage here
Post.new(title, text, tag_repository.find(tag_ids)) # or tag_names or tag_something
end
Looks better. But is it fine to make separate repository for value-objects?
What is the right way according DDD?
UPD:
In other hand, I have to get all available tags. And I never have to change tag with posts. And tags' name looks like identity. Maybe I'm fundamentally wrong? Maybe tag is entity?
UPD2:
This problem shows me that my design skill is very poor.
Because of it, there is two question in my one.
They are:
What is right way to build value object inside entities' repository.
How to see the difference between value and entity in my problem.
After all it looks clear. According the specified conditions, tag is value. And it's ok that it's builded by Post's repository.
But this conditions is result of poor analize. If I could look wider, I would see that tag has it's own life cycle. Though, in context of post, tags are immutable.
Tag is most probably just a regular value object in your domain. Tag could be an entity, if it had its own lifecycle. Frankly, I don't think that's the case in your domain, as you can replace each tag with another copy with the same properties.
You can add methods to query tags to your domain repository. It's not a violation of DDD aggregate rules. Aggregates are really about consistency - your repositories should not return parts of your aggregate if you can modify them outside of aggregate context. However, you can explicitly return value objects of your aggregates just for read purposes (e.g. collecting all tags of all posts within selected date range). Besides that, query methods should be placed inside repository for the sake of efficiency. That being said, in your case probably the best solution is to use separate read model (using e.g. nosql db) following CQRS principles. This way you have the model explicitly adjusted to your query needs, so it can very efficient.

stackoverflow tag problem Vo or entity or seperate root agg

In the context of domain driven design, tag in stackoverflow is value type, see below link discussion.
DDD: SO tag. An Entity or value type?
But if it is value type then in future if any one wants to create new tag, how will he perform that ?
in my project is also there is tag which is associated with an advertisement entity, 1 to many, but if i consider tag as a value type and in future if i want to add new tag in data base . How would i do that, because tag is VO. while creating advertisement i can only assign existing tag to a new advertisement , but how will i create new tag?
In the context of the list of possible tags, tag is an entity.
A tag as applied to a question is a value type. In fact, it's not even a class from the order's perspective - it's really just a string.
Tag is an entity. It has conceptual identity, please see my answer. You create it just like you create any other entities.

How to find related items by tags in Lucene.NET

My indexed documents have a field containing a pipe-delimited set of ids:
a845497737704e8ab439dd410e7f1328|
0a2d7192f75148cca89b6df58fcf2e54|
204fce58c936434598f7bd7eccf11771
(ignore line breaks)
This field represents a list of tags. The list may contain 0 to n tag Ids.
When users of my site view a particular document, I want to display a list of related documents.
This list of related document must be determined by tags:
Only documents with at least one matching tag should appear in the "related documents" list.
Document with the most matching tags should appear at the top of the "related documents" list.
I was thinking of using a WildcardQuery for this but queries starting with '*' are not allowed.
Any suggestions?
Setting aside for a minute the possible uses of Lucene for this task (which I am not overly familiar with) - consider checking out the LinkDatabase.
Sitecore will, behind the scenes, track all your references to and from items. And since your multiple tags are indeed (I assume) selected from a meta hierarchy of tags represented as Sitecore Items somewhere - the LinkDatabase would be able to tell you all items referencing it.
In some sort of pseudo code mockup, this would then become
for each ID in tags
get all documents referencing this tag
for each document found
if master-list contains document; increase usage-count
else; add document to master list
sort master-list by usage-count descending
Forgive me that I am not more precise, but am unavailable to mock up a fully working example right at this stage.
You can find an article about the LinkDatabase here http://larsnielsen.blogspirit.com/tag/XSLT. Be aware that if you're tagging documents using a TreeListEx field, there is a known flaw in earlier versions of Sitecore. Documented here: http://www.cassidy.dk/blog/sitecore/2008/12/treelistex-not-registering-links-in.html
Your pipe-delimited set of ids should really have been separated into individual fields when the documents were indexed. This way, you could simply do a query for the desired tag, sorting by relevance descending.
You can have the same field multiple times in a document. In this case, you would add multiple "tag" fields at index time by splitting on |. Then, when you search, you just have to search on the "tag" field.
Try this query on the tag field.
+(tag1 OR tag2 OR ... tagN)
where tag1, .. tagN are the tags of a document.
This query will return documents with at least one tag match. The scoring automatically will take care to bring up the documents with highest number of matches as the final score is sum of individual scores.
Also, you need to realizes that if you want to find documents similar to tags of Doc1, you will find Doc1 coming at the top of the search results. So, handle this case accordingly.

DDD: SO tag. An Entity or value type?

In the context of Domain Driven Design, is a StackOverflow tag (ie. ddd ) a value object or entity?
EDIT:
Imagine, that you have to build SO website. How would you consider 'tag'?
To expand a little on awhite's answer
a tag is a value type
Why?
Because it doesn't make sense to have
var tag1 = new Tag("DDD");
var tag2 = new Tag("DDD");
Assert.AreNotEqual(tag1, tag2);
clearly they should be equal to each other because a tag has no identity except for its label. Questions and answers on the other hand are definitely entities
SO tag is most likely an entity. Tags can be created, merged, deleted and renamed. There are features like 'similar tags', user's tags etc. Some of these functions, especially life cycle, will require an identity. Classic DDD example where Person that changes his/her name is still the same person, the same identity. The same with tags where user can decide to rename "domain-driven-design" to "DDD" and it will still be the same thing. Tags also need additional attributes like tag.Id, tag.Name, tag.CreatedOn, tag.CreatedBy, tag.Locked etc. There would probably be a corresponding tags repository that can enforce name uniqueness rule.
To summarize, SO Tag is not a DDD Value Object because it is mutable and has a life cycle. More importantly, Tag is not only a characteristic of a Question (this is what I think was overlooked by other answers). It participates in a lot more relationships than that. In other words, Tag is more than just a sum of its attributes, it also has 'conceptual identity'. On the other hand TagName is a perfect example of Value Object. Its only purpose in life is to describe another entity (Tag). TagName is nothing more than just a string that may have a few built in rules like max length and case insensitive comparison. It may also make sense to simply use String instead.
Code that displays questions may use something like this:
IList<TagName> tags = question.GetTags();
Code that tags the question can look like this:
void TagQuestion(Question q, TagName tagName) {
Tag tag = _tagsRepository.FindByName(tagName);
if (tag == null) {
tag = CreateNewTag( /* capture creator, date, other rules*/);
}
q.AddTag(tag);
}
Just some additional considerations: Tags can be normalized, "DDD" should be equal to "ddd" and "DdD", and in most tag systems, spaces get replaced with "_" underscores. Also I guess the creator will be tracked for the badge system.

Resources