From 8e06adb1abd24e794b5be19124dc481c3e3040ee Mon Sep 17 00:00:00 2001 From: Nurhak Tuekek Date: Thu, 9 May 2024 17:47:43 +0200 Subject: [PATCH 1/6] added explanation for the setFullName Function --- synchronizations/Family2Person.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/synchronizations/Family2Person.md b/synchronizations/Family2Person.md index af744ed..7554656 100644 --- a/synchronizations/Family2Person.md +++ b/synchronizations/Family2Person.md @@ -317,6 +317,27 @@ registrations. - If the member's name is null, null is returned. - The `GetFullName()` method is defined as an extension method for objects of type IFamilyMember. - The Evaluate function returns an observable value that keeps track of any changes + ```csharp + public static void SetFullName(this IFamilyMember member, string newName) + { + var family = member.Parent as IFamily; + var separator = newName.IndexOf(", "); + var lastName = newName.Substring(0, separator); + var firstName = newName.Substring(separator + 2); + member.Name = firstName; + if (family != null && family.Name != lastName) + { + var isMale = member.FatherInverse != null || member.SonsInverse != null; + member.AddToFamily(family.FamiliesInverse, isMale, lastName); + } + } + ``` + - Extension Method: This method extends objects that implement the IFamilyMember interface. + - Retrieve Family Information:It retrieves the family information associated with the member by accessing its Parent property, assuming it implements IFamily. + - Parse Full Name: It parses the full name passed as a parameter (newName) by finding the index of the separator (", ") to split the string into last name and first name. + - Set First Name: It sets the first name of the member to the parsed first name. + - Check and Update Family Information:If the family is not null and the last name extracted from the full name does not match the family's name, it implies the member is associated with a different family. + - Add Member to Correct Family: If necessary, it determines whether the member is male based on whether it has a father or sons, and then adds the member to the correct family by invoking the AddToFamily method with appropriate parameters. - Summary: In summary, the synchronization process involves calling the Synchronize method on the synchronization instance, using specific synchronization rules (FamilyRegisterToPersonRegister and MemberToMember) to synchronize data between instances of FamilyRegister, PersonRegister, IFamilyMember, and IPerson. The synchronization is bidirectional and prioritizes changes from the left model (familyRegister). - The rest of the constructor is equivalent to the FirstNmfProject initialization. Adding the registry classes as RootElements and Adding the empty Models. From 80faa0741b4dec3d3ecb3b7e8abc0ee16f47e9a3 Mon Sep 17 00:00:00 2001 From: Nurhak Tuekek Date: Thu, 23 May 2024 15:20:30 +0200 Subject: [PATCH 2/6] added explanations to symchronisation --- synchronizations/Family2Person.md | 370 +--------------------------- synchronizations/Synchronization.md | 221 +++++++++++++++++ synchronizations/toc.yml | 3 + 3 files changed, 225 insertions(+), 369 deletions(-) create mode 100644 synchronizations/Synchronization.md diff --git a/synchronizations/Family2Person.md b/synchronizations/Family2Person.md index 7554656..cfe4132 100644 --- a/synchronizations/Family2Person.md +++ b/synchronizations/Family2Person.md @@ -17,372 +17,4 @@ Consistency between the families and persons models is defined by a bijective ma In incremental transformations, various updates are considered. Forward updates involve the insertion, deletion, renaming, or moving of families and members. Backward updates, affected by dynamic configuration parameters, include deletion, insertion, and changes in name, but not birthdays. These transformations exemplify a round-trip engineering scenario, requiring bidirectional updates. [Click here to see the complete TTC solution](https://sdq.kastel.kit.edu/publications/pdfs/hinkel2017f.pdf) -## Tutorial -![EMF Diagrams](images/EMFDiagrams.png) - -We generate the corresponding Ecore files from the two class diagrams shown above. One for the family model and one for the person model. -We then generate the NMF models and classes, configure our .csproj file and load our models into the Program.cs file analogous to -[Starting our first project](../models/FirstNmfProject.md) - -We have to add a file named `Families2PersonsSynchronization.cs` that looks like this: -```csharp -class Families2PersonsSynchronization : ReflectiveSynchronization - { - public class FamilyRegisterToPersonRegister : SynchronizationRule - { - // Synchronization Block - public override void DeclareSynchronization() - { - SynchronizeMany(SyncRule(), - fam => new FamilyMemberCollection(fam), - persons => persons.Persons); - } - } - - public class MemberToMember : SynchronizationRule - { - public override void DeclareSynchronization() - { - Synchronize(m => m.GetFullName(), p => p.Name); - } - } - - public class MemberToMale : SynchronizationRule - { - public override void DeclareSynchronization() - { - MarkInstantiatingFor(SyncRule(), leftPredicate: m => m.FatherInverse != null || m.SonsInverse != null); - } - - protected override IFamilyMember CreateLeftOutput(IMale input, IEnumerable candidates, ISynchronizationContext context, out bool existing) - { - var member = base.CreateLeftOutput(input, candidates, context, out existing); - member.Extensions.Add(new TemporaryStereotype(member) - { - IsMale = true, - LastName = input.Name.Substring(0, input.Name.IndexOf(',')) - }); - return member; - } - } - - public class MemberToFemale : SynchronizationRule - { - public override void DeclareSynchronization() - { - MarkInstantiatingFor(SyncRule(), leftPredicate: m => m.MotherInverse != null || m.DaughtersInverse != null); - } - - protected override IFamilyMember CreateLeftOutput(IFemale input, IEnumerable candidates, ISynchronizationContext context, out bool existing) - { - var member = base.CreateLeftOutput(input, candidates, context, out existing); - member.Extensions.Add(new TemporaryStereotype(member) - { - IsMale = false, - LastName = input.Name.Substring(0, input.Name.IndexOf(',')) - }); - return member; - } - - // should this two model elements be linked, if so define a rule for shared attributes like name, ... - public override bool ShouldCorrespond(IFamilyMember left, IFemale right, ISynchronizationContext context) - { - if (left.Name == right.Name) { - return true; - } - return false; - } - } - - private class FamilyMemberCollection : CustomCollection - { - public FamilyRegister Register { get; private set; } - - public FamilyMemberCollection(FamilyRegister register) - : base(register.Families.SelectMany(fam => fam.Children.OfType())) - { - Register = register; - } - - public override void Add(IFamilyMember item) - { - var temp = item.GetExtension(); - item.AddToFamily(Register, temp.IsMale, temp.LastName); - item.Extensions.Remove(temp); - } - - public override void Clear() - { - Register.Families.Clear(); - } - - public override bool Remove(IFamilyMember item) - { - item.Delete(); - return true; - } - } - } - - public class TemporaryStereotype : ModelElementExtension - { - public bool IsMale { get; set; } - - public string LastName { get; set; } - - public TemporaryStereotype(IFamilyMember parent) - { - parent.Extensions.Add(this); - } - - public override IExtension GetExtension() { return null; } - } - - public static class Helpers - { - public static bool PreferCreatingParentToChild = true; - public static bool PreferExistingFamilyToNew = true; - - private static ObservingFunc fullName = new ObservingFunc( - m => m.Name == null ? null : ((IFamily)m.Parent).Name + ", " + m.Name); - - [LensPut(typeof(Helpers), "SetFullName")] - [ObservableProxy(typeof(Helpers), "GetFullNameInc")] - public static string GetFullName(this IFamilyMember member) - { - return fullName.Evaluate(member); - } - - public static INotifyValue GetFullNameInc(this IFamilyMember member) - { - return fullName.Observe(member); - } - - public static void AddToFamily(this IFamilyMember item, IFamilyRegister register, bool isMale, string name) - { - IFamily family = null; - if (PreferExistingFamilyToNew) - { - IEnumerable candidateFamilies = register.Families.AsEnumerable().Where(fam => fam.Name == name); - if (PreferCreatingParentToChild) - { - if (isMale) - { - family = candidateFamilies.Where(fam => fam.Father == null).FirstOrDefault(); - } - else - { - family = candidateFamilies.Where(fam => fam.Mother == null).FirstOrDefault(); - } - } - family = family ?? candidateFamilies.FirstOrDefault(); - } - if (family == null) - { - family = new Family { Name = name }; - register.Families.Add(family); - } - if (isMale) - { - if (family.Father == null && PreferCreatingParentToChild) - { - family.Father = item; - } - else - { - family.Sons.Add(item); - } - } - else - { - if (family.Mother == null && PreferCreatingParentToChild) - { - family.Mother = item; - } - else - { - family.Daughters.Add(item); - } - } - } - - public static void SetFullName(this IFamilyMember member, string newName) - { - var family = member.Parent as IFamily; - var separator = newName.IndexOf(", "); - var lastName = newName.Substring(0, separator); - var firstName = newName.Substring(separator + 2); - member.Name = firstName; - if (family != null && family.Name != lastName) - { - var isMale = member.FatherInverse != null || member.SonsInverse != null; - member.AddToFamily(family.FamiliesInverse, isMale, lastName); - } - } - } -``` -This file defines our Synchronization logic between the 2 models. A further explanation will follow with some examples in the next part of the tutorial. - -We modify the Program.cs as follows: -```csharp -class Program - { - private FamilyRegister familyRegister; - private PersonRegister personRegister; - - private ModelRepository repository = new ModelRepository(); - - private Families2PersonsSynchronization synchronization = new Families2PersonsSynchronization(); - - public Program() - { - var familyRootModel = new Model(); - var personRootModel = new Model(); - - familyRegister = new FamilyRegister(); - personRegister = new PersonRegister(); - - synchronization.Synchronize( - synchronization.SynchronizationRule(), - ref familyRegister, // Familyregister is the left model - ref personRegister, // Personregister is the right model - SynchronizationDirection.LeftWins, // prioritizes the left synchronization of left model (without shouldCorrespond it has no impact) - ChangePropagationMode.TwoWay); // TwoWay means Bidirectional synchronization - - familyRootModel.RootElements.Add(familyRegister); - personRootModel.RootElements.Add(personRegister); - - repository.Models.Add(new Uri("ttc:source"), familyRootModel); - repository.Models.Add(new Uri("ttc:target"), personRootModel); - } - - static void Main(string[] args) - { - } - } -``` -A short explanation to the code. -1. Attributes -- `familyRegister` and `personRegister` are private class members representing instances of classes, used for managing family and person -registrations. -- `repository` is an instance of the [ModelRepository](../models/api/NMF.Models.Repository.ModelRepository.yml) class, responsible for managing models. -- `synchronization` is an instance of the `Families2PersonsSynchronization` class, designed for synchronizing data between family and person registers. - -2. Constructor -- Two instances of the Model class (`familyRootModel` and `personRootModel`) are created. These will serve as root models for family and person registers. -- Instances of classes (`FamilyRegister` and `PersonRegister`) are created and assigned to `familyRegister` and `personRegister`. -- ## Synchonization: - - The [Synchronize](../synchronizations/api/NMF.Synchronizations.Synchronization.yml) method is called on the `synchronization` instance. - - It uses the synchronization rule `Families2PersonsSynchronization.FamilyRegisterToPersonRegister`. - - `ref familyRegister` represents the left model, and `ref personRegister` represents the right model. - - `SynchronizationDirection.LeftWins` [Synchronization Api](../synchronizations/api/NMF.Synchronizations.SynchronizationDirection.yml) is used, prioritizing changes from the left model (familyRegister) in case of conflicts. (without shouldCorrespond it has no impact) - - `ChangePropagationMode.TwoWay` [Transformation Api](../transformations/api/NMF.Transformations.ChangePropagationMode.yml) indicates bidirectional (two-way) synchronization, allowing changes in both directions. - - `FamilyRegisterToPersonRegister` Class: - ```csharp - public class FamilyRegisterToPersonRegister : SynchronizationRule - { - // Synchronization Block - public override void DeclareSynchronization() - { - SynchronizeMany(SyncRule(), - fam => new FamilyMemberCollection(fam), - persons => persons.Persons); - } - } - ``` - - This class extends `SynchronizationRule` [Synchronization Rules](../synchronizations/api/NMF.Synchronizations.SynchronizationRule-2.yml) and is designed for synchronizing instances of `FamilyRegister` to `PersonRegister`. - - The `DeclareSynchronization` method is overridden, and it declares synchronization instructions using `SynchronizeMany` [Synchronization Rules](../synchronizations/api/NMF.Synchronizations.SynchronizationRule-2.yml) - - `MemberToMember` Class: - ```csharp - public class MemberToMember : SynchronizationRule - { - public override void DeclareSynchronization() - { - Synchronize(m => m.GetFullName(), p => p.Name); - } - } - ``` - - This class extends `SynchronizationRule` [Synchronization Rules](../synchronizations/api/NMF.Synchronizations.SynchronizationRule-2.yml) and is designed for synchronizing instances of types implementing `IFamilyMember` to `IPerson` - - The `DeclareSynchronization` method is overridden, and it declares `synchronization` instructions using `Synchronize`. - - It synchronizes the result of calling `m.GetFullName()` on the left side to `p.Name` on the right side. - ```csharp - public static string GetFullName(this IFamilyMember member) - { - return fullName.Evaluate(member); - } - ``` - - This method returns the full name of a family member. - - It accesses the static variable fullName, which is a function of the type `ObservingFunc` [Expression](../expressions/api/NMF.Expressions.ObservingFunc-10.yml). - - The fullName function is used to create the full name of the member. The name is composed of the member's name and the name of their family, separated by a comma. - - If the member's name is null, null is returned. - - The `GetFullName()` method is defined as an extension method for objects of type IFamilyMember. - - The Evaluate function returns an observable value that keeps track of any changes - ```csharp - public static void SetFullName(this IFamilyMember member, string newName) - { - var family = member.Parent as IFamily; - var separator = newName.IndexOf(", "); - var lastName = newName.Substring(0, separator); - var firstName = newName.Substring(separator + 2); - member.Name = firstName; - if (family != null && family.Name != lastName) - { - var isMale = member.FatherInverse != null || member.SonsInverse != null; - member.AddToFamily(family.FamiliesInverse, isMale, lastName); - } - } - ``` - - Extension Method: This method extends objects that implement the IFamilyMember interface. - - Retrieve Family Information:It retrieves the family information associated with the member by accessing its Parent property, assuming it implements IFamily. - - Parse Full Name: It parses the full name passed as a parameter (newName) by finding the index of the separator (", ") to split the string into last name and first name. - - Set First Name: It sets the first name of the member to the parsed first name. - - Check and Update Family Information:If the family is not null and the last name extracted from the full name does not match the family's name, it implies the member is associated with a different family. - - Add Member to Correct Family: If necessary, it determines whether the member is male based on whether it has a father or sons, and then adds the member to the correct family by invoking the AddToFamily method with appropriate parameters. - - Summary: In summary, the synchronization process involves calling the Synchronize method on the synchronization instance, using specific synchronization rules (FamilyRegisterToPersonRegister and MemberToMember) to synchronize data between instances of FamilyRegister, PersonRegister, IFamilyMember, and IPerson. The synchronization is bidirectional and prioritizes changes from the left model (familyRegister). -- The rest of the constructor is equivalent to the FirstNmfProject initialization. Adding the registry classes as RootElements and Adding the empty Models. - - - -To get a better understanding of synchronization, let's illustrate the whole thing with an example. The example looks like this: -```csharp -static void Main(string[] args) - { - // 1. First case Bidirectional synchronization. - var program = new Program(); - program.familyRegister.Families.Add(new Family { - Father = new FamilyMember { - Name = "Marx" - }, - Name = "Mustermann" - }); - - var fatherFirstName = program.familyRegister.Families.First().Father; - var familyName = program.familyRegister.Families.First().Name; - - var person = program.personRegister.Persons.First().Name; - - Console.WriteLine(fatherFirstName); // FamilyMember 'Marx' - Console.WriteLine(familyName); // Mustermann - Console.WriteLine(person); // Mustermann, Marx - } -``` -But how does this happen? The answer is: -When `FamilyRegisterToPersonRegister` is invoked, it synchronizes the members of each family to persons. -Since you're using `SynchronizeMany` [Synchronization Rules](../synchronizations/api/NMF.Synchronizations.SynchronizationRule-2.yml), it synchronizes each member of the family to a person. -Each `FamilyMember` in `FamilyRegister` is synchronized with an `IPerson` in `PersonRegister` based on their full names. -So, when you add a Family to familyRegister, each FamilyMember within that family gets synchronized and added to personRegister as a Person with the corresponding name. - -The same works the other way around: -```csharp - // 2. synchronization from person to family. - program.personRegister.Persons.Add(new Male{ - Name = "Smith, John" - }); - - var smith = program.familyRegister.Families.Reverse().First().Name; - var john = program.familyRegister.Families.Reverse().First().Father; - Console.WriteLine(smith); // Smith - Console.WriteLine(john); // FamilyMember 'John' -``` -We can see from the definition of the synchronization rule that the newly added person also gets registered as a new family with the name Smith and their members. - +[Click here to get to the Tutorial](./Synchronization.md) \ No newline at end of file diff --git a/synchronizations/Synchronization.md b/synchronizations/Synchronization.md new file mode 100644 index 0000000..9089026 --- /dev/null +++ b/synchronizations/Synchronization.md @@ -0,0 +1,221 @@ +## Tutorial +![EMF Diagrams](images/EMFDiagrams.png) + +We generate the corresponding Ecore files from the two class diagrams shown above. One for the family model and one for the person model. +We then generate the NMF models and classes, configure our .csproj file and load our models into the Program.cs file analogous to +[Starting our first project](../models/FirstNmfProject.md) + +The first step is to create a file in which we define the synchronization logic of the two models. We name this file `Families2PersonsSynchronization.cs`. + +Let's think about what we need for our example. For this, let's look at the class diagram and draw the following conclusions. We need the FamilyRegister, the PersonRegister, and the Synchronization class where the synchronization logic between Family and Person is defined. +```csharp +class Program + { + private FamilyRegister familyRegister; + private PersonRegister personRegister; + + private ModelRepository repository = new ModelRepository(); + + private Families2PersonsSynchronization synchronization = new Families2PersonsSynchronization(); + + static void Main(string[] args) + { + } + } +``` + +Next, we need to consider how the initialization should look. In our example, this will take place in the class constructor. + +```csharp +public Program() + { + var familyRootModel = new Model(); + var personRootModel = new Model(); + + familyRegister = new FamilyRegister(); + personRegister = new PersonRegister(); + + synchronization.Synchronize( + synchronization.SynchronizationRule(), + ref familyRegister, // Familyregister is the left model + ref personRegister, // Personregister is the right model + SynchronizationDirection.LeftWins, // prioritizes the left synchronization of left model (without shouldCorrespond it has no impact) + ChangePropagationMode.TwoWay); // TwoWay means Bidirectional synchronization + + familyRootModel.RootElements.Add(familyRegister); + personRootModel.RootElements.Add(personRegister); + + repository.Models.Add(new Uri("ttc:source"), familyRootModel); + repository.Models.Add(new Uri("ttc:target"), personRootModel); + } +``` + +Here, we are creating two instances of the [Model](../models/api/NMF.Models.Model.yml) class. These instances, `familyRootModel` and `personRootModel`, are initially empty. In our case, these models represent the root nodes in a tree-like structure. + +We then create instances of `FamilyRegister` and `PersonRegister`. These registers are child nodes of the models, and they manage specific types of data, in our case Familymembers and Persons: +- `FamilyRegister`: As the name suggests, this register manages families. A family, in this context, consists of a parent couple (mother and father) and can have children. +- `PersonRegister`: This register manages individual persons. These persons form the foundation for families, as each family is composed of individuals. + + +```csharp +synchronization.Synchronize( + synchronization.SynchronizationRule(), // synchronization block/rule + ref familyRegister, // Familyregister is the left model + ref personRegister, // Personregister is the right model + SynchronizationDirection.LeftWins, // prioritizes the left synchronization of left model (without shouldCorrespond it has no impact) + ChangePropagationMode.TwoWay); // TwoWay means Bidirectional synchronization +``` +Synchronization Method Call: + The `Synchronize()` method is invoked on the synchronization object to establish synchronization between two models. + This method configures how data is synchronized between the models. +Synchronization Rule: + The synchronization rule, `FamilyRegisterToPersonRegister`, is specified from the `Families2PersonsSynchronization` class. + It defines the logic for mapping data between the family register and the person register. +Adding Registers: + Both the family register and the person register are passed as parameters to the Synchronize method. + The family register is considered the left model, and the person register is considered the right model. +Synchronization Direction: + The synchronization direction is set to LeftWins, indicating that the left model's values take precedence during synchronization. + This ensures that conflicts are resolved in favor of the left model's data. +Change Propagation Mode: + The change propagation mode is set to TwoWay, indicating bidirectional synchronization. + Changes can propagate in both directions, allowing both models to react to each other's updates. + + +```csharp +familyRootModel.RootElements.Add(familyRegister); +personRootModel.RootElements.Add(personRegister); + +repository.Models.Add(new Uri("ttc:source"), familyRootModel); +repository.Models.Add(new Uri("ttc:target"), personRootModel); +``` +In the next step, we will build our 'tree' by storing the registries in the models. Subsequently, these generated and populated models will be saved. + + +Then, our Program.cs looks like this. +```csharp +class Program + { + private FamilyRegister familyRegister; + private PersonRegister personRegister; + + private ModelRepository repository = new ModelRepository(); + + private Families2PersonsSynchronization synchronization = new Families2PersonsSynchronization(); + + public Program() + { + var familyRootModel = new Model(); + var personRootModel = new Model(); + + familyRegister = new FamilyRegister(); + personRegister = new PersonRegister(); + + synchronization.Synchronize( + synchronization.SynchronizationRule(), + ref familyRegister, // Familyregister is the left model + ref personRegister, // Personregister is the right model + SynchronizationDirection.LeftWins, // prioritizes the left synchronization of left model (without shouldCorrespond it has no impact) + ChangePropagationMode.TwoWay); // TwoWay means Bidirectional synchronization + + familyRootModel.RootElements.Add(familyRegister); + personRootModel.RootElements.Add(personRegister); + + repository.Models.Add(new Uri("ttc:source"), familyRootModel); + repository.Models.Add(new Uri("ttc:target"), personRootModel); + } + + static void Main(string[] args) + {} + } +``` + +## Synchronization + +As described above, in this section, we specifically address the synchronization rule/block. + +```csharp +synchronization.SynchronizationRule() +``` + +The line signifies that a synchronization rule is being invoked, with its type being `Families2PersonsSynchronization.FamilyRegisterToPersonRegister`. This rule leverages the synchronization block, which is defined within the Families2PersonsSynchronization class. + +Lets take a closer a look at the synchronization block. +```csharp +public class FamilyRegisterToPersonRegister : SynchronizationRule + { + // Synchronization Block + public override void DeclareSynchronization() + { + SynchronizeMany(SyncRule(), + fam => new FamilyMemberCollection(fam), + persons => persons.Persons); + } + } +``` +This method named [SynchronizeMany](../synchronizations/api/NMF.Synchronizations.SynchronizationRuleBase.yml) facilitates bidirectional synchronization, implying that the method itself defines a dependency between both models. It synchronizes dependent elements using a synchronization rule, accepting a rule, left and right selectors in the model, and the types of dependent elements. Then, it initiates synchronization using the provided parameters. + + +```csharp +public class MemberToMember : SynchronizationRule + { + // Synchronization block for a familymember and a person + public override void DeclareSynchronization() + { + Synchronize(m => m.GetFullName(), p => p.Name); + } + } +``` +The block defines how individual objects should be synchronized with each other. +In this example, people and family members are being synchronized. The synchronization is based on one or more attributes that are the same. A shared attribute between Person and FamilyMember is the attribute `name`, which is why the synchronization is based on the `name` attribute of both classes. + + + +Next, let's take a closer look at the `GetFullName` method. + +```csharp +[LensPut(typeof(Helpers), "SetFullName")] // is called when GetFullName is called +[ObservableProxy(typeof(Helpers), "GetFullNameInc")] // connected mit INotifyValue +public static string GetFullName(this IFamilyMember member) +{ + return fullName.Evaluate(member); +} +``` + +Let's first have a look at the fullName attribute +```csharp +private static ObservingFunc fullName = new ObservingFunc(m => m.Name == null ? null : ((IFamily)m.Parent).Name + ", " + m.Name); +``` +This expression defines a static field `fullName` of type `ObservingFunc`. It's initialized with a lambda function that takes an `IFamilyMember` object m and returns a string representing the member's full name. If the member's name is not null, it concatenates the family name with the member's name, separated by a comma. If the member's name is null, it returns null. + +```csharp +[LensPut(typeof(Helpers), "SetFullName")] // is called when GetFullName is called +[ObservableProxy(typeof(Helpers), "GetFullNameInc")] // connected mit INotifyValue +``` +`ObservableProxy`: + The annotations indicate that the `fullName` variable is constantly observed. This means that through the `GetFullNameInc` function with the parameter type `INotifyValue`, the `fullName` of the family member is continuously monitored. Upon any changes, the family member is notified, and the changes are propagated in real-time. +`LensPut`: + `LensPut` ensures that the `SetFullName` method is always executed whenever the `GetFullName` method is used. + +```csharp +public static void SetFullName(this IFamilyMember member, string newName) +{ + var family = member.Parent as IFamily; + var separator = newName.IndexOf(", "); + var lastName = newName.Substring(0, separator); + var firstName = newName.Substring(separator + 2); + member.Name = firstName; + if (family != null && family.Name != lastName) + { + var isMale = member.FatherInverse != null || member.SonsInverse != null; + member.AddToFamily(family.FamiliesInverse, isMale, lastName); + } +} +``` +The `SetFullName` method is an extension method designed for objects implementing the `IFamilyMember` interface. When invoked, it first retrieves the associated family of the member. Assuming the full name is structured as "Last Name, First Name", it parses the `newName` parameter to extract the last and first names accordingly. Subsequently, it updates the member's Name property with the extracted first name. Additionally, if the associated family exists and its name differs from the extracted last name, it determines the member's gender based on familial relationships and adds the member to the family's collection, specifying the gender and the extracted last name. This method effectively manages the synchronization of the full name and family association of a family member. \ No newline at end of file diff --git a/synchronizations/toc.yml b/synchronizations/toc.yml index 70be5ab..3ed6af4 100644 --- a/synchronizations/toc.yml +++ b/synchronizations/toc.yml @@ -15,5 +15,8 @@ href: FiniteStateMachines2PetriNetsTutorial.md - name: Family2Person href: Family2Person.md + items: + - name: Synchronization + href: Synchronization.md - name: API href: api/toc.yml \ No newline at end of file From e62459b7b79dd53618dbc846d9ce7912019c61f6 Mon Sep 17 00:00:00 2001 From: Nurhak Tuekek Date: Thu, 23 May 2024 15:35:13 +0200 Subject: [PATCH 3/6] added tutorial link --- synchronizations/Synchronization.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/synchronizations/Synchronization.md b/synchronizations/Synchronization.md index 9089026..0cfd00e 100644 --- a/synchronizations/Synchronization.md +++ b/synchronizations/Synchronization.md @@ -218,4 +218,6 @@ public static void SetFullName(this IFamilyMember member, string newName) } } ``` -The `SetFullName` method is an extension method designed for objects implementing the `IFamilyMember` interface. When invoked, it first retrieves the associated family of the member. Assuming the full name is structured as "Last Name, First Name", it parses the `newName` parameter to extract the last and first names accordingly. Subsequently, it updates the member's Name property with the extracted first name. Additionally, if the associated family exists and its name differs from the extracted last name, it determines the member's gender based on familial relationships and adds the member to the family's collection, specifying the gender and the extracted last name. This method effectively manages the synchronization of the full name and family association of a family member. \ No newline at end of file +The `SetFullName` method is an extension method designed for objects implementing the `IFamilyMember` interface. When invoked, it first retrieves the associated family of the member. Assuming the full name is structured as "Last Name, First Name", it parses the `newName` parameter to extract the last and first names accordingly. Subsequently, it updates the member's Name property with the extracted first name. Additionally, if the associated family exists and its name differs from the extracted last name, it determines the member's gender based on familial relationships and adds the member to the family's collection, specifying the gender and the extracted last name. This method effectively manages the synchronization of the full name and family association of a family member. + +## Github Tutorial: [hier](https://github.com/Cemtk6246/Family2Person) \ No newline at end of file From 59f92121f1dac2c532da5ef0acc8c160efcce1f9 Mon Sep 17 00:00:00 2001 From: Nurhak Tuekek Date: Fri, 24 May 2024 14:11:21 +0200 Subject: [PATCH 4/6] changed german words --- synchronizations/Synchronization.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/synchronizations/Synchronization.md b/synchronizations/Synchronization.md index 0cfd00e..b21878e 100644 --- a/synchronizations/Synchronization.md +++ b/synchronizations/Synchronization.md @@ -196,7 +196,7 @@ This expression defines a static field `fullName` of type `ObservingFunc Date: Thu, 12 Sep 2024 13:42:39 +0200 Subject: [PATCH 5/6] changes --- synchronizations/Synchronization.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/synchronizations/Synchronization.md b/synchronizations/Synchronization.md index b21878e..5ec382d 100644 --- a/synchronizations/Synchronization.md +++ b/synchronizations/Synchronization.md @@ -45,8 +45,8 @@ public Program() familyRootModel.RootElements.Add(familyRegister); personRootModel.RootElements.Add(personRegister); - repository.Models.Add(new Uri("ttc:source"), familyRootModel); - repository.Models.Add(new Uri("ttc:target"), personRootModel); + repository.Models.Add(new Uri("example/Uri"), familyRootModel); + repository.Models.Add(new Uri("example/URI"), personRootModel); } ``` @@ -80,6 +80,7 @@ Synchronization Direction: Change Propagation Mode: The change propagation mode is set to TwoWay, indicating bidirectional synchronization. Changes can propagate in both directions, allowing both models to react to each other's updates. +The idea is that you declare that these two model elements are corresponding to each other ```csharp @@ -153,8 +154,7 @@ public class FamilyRegisterToPersonRegister : SynchronizationRule @@ -173,7 +173,7 @@ In this example, people and family members are being synchronized. The synchroni **Note:** -At this point, it can be added that when synchronizing between a family and a person register that are already populated, the collision rule applies. For example, there is a man named Smith who marries a woman named Muster. As a result, the woman appears as Smith in the family register and as Muster in the person register. This leads to a collision, and the left side (family register) wins, so the woman's name in the person register is changed to Smith. +At this point, it can be added that when synchronizing between a family and a person register that are already populated, the collision rule applies. For example, there is a man named Smith who marries a woman named Muster. As a result, the woman appears as Smith in the family register and as Muster in the person register. This leads to a collision, and the left side (family register) wins, so the woman's name in the person register is changed to Smith. This is only important for the initial synchronization. @@ -199,7 +199,7 @@ This expression defines a static field `fullName` of type `ObservingFunc Date: Thu, 12 Sep 2024 14:00:35 +0200 Subject: [PATCH 6/6] change --- synchronizations/Synchronization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synchronizations/Synchronization.md b/synchronizations/Synchronization.md index 5ec382d..0ccb451 100644 --- a/synchronizations/Synchronization.md +++ b/synchronizations/Synchronization.md @@ -24,7 +24,7 @@ class Program } ``` -Next, we need to consider how the initialization should look. In our example, this will take place in the class constructor. +Next, we need to consider how the initialization should look like. In our example, this will take place in the class constructor. ```csharp public Program()