Would this be for a Development System or a Production System?

If it is a Development System you could consider using source control hooks to basically prevent people from modifying the class unless they first check out the file. If they attempt to modify it without first checking it out, they will get a message saying they need to first check out the file. If they do not have permission to do so, they will not be able to. If they do have permission to, using source control will allow you to revert any changes that end up causing issues.

If it is a Production System, you can consider using deployed mode. See documentation here. The documentation says: "You can open the class definition in Atelier, but it is read-only." (This is true for Studio also).

As you mention, making the Database Read Only is also an option.

By the way, after running the populate method, the test method outputs the following:

SAMPLES>do ##class(DCSolutions.TwoWayJSONAdaptor.TeacherStudent).Test()

Hi Nael,

I was able to make this work using an XData Map (Documentation here). I have uploaded my Sample to GitHub so you can see how I implemented it. I will also summarize what I did here:

This Sample uses 3 classes: Teacher, Student, and TeacherStudent. As you describe and as your JSON output suggests, Teacher and Student have a reference to TeacherStudent, which simply has an ID. To allow this to output the link to the next object (depending on the direction) I had to use Calculated properties. This means I can access data from TeacherStudent, but I am not storing the references again. The calculations to get the Teacher/Student are pretty simple, just an SQL statement to get the related record. At this point, if you try and use %JSONExport() on a student, it will print out the teachers as expected, but then the teachers print out all the students, and the students print the teachers again. This continues until reaching an error.

To avoid this, I used the XData Map. One map for "Student" and one map for "Teacher". Each is named based on the starting point. When using the Teacher map, the Teacher class will output the name and the link to TeacherStudent. TeacherStudent will then output the name and the link to Student. Student will then output only the name and will not link back to TeacherStudent. The same is true for using the Student map for Student (but going the other way).

I hope this accomplishes what you are looking for!


Here are a couple of ways for getting information about a file:

Get file size:

set file=##class(%Stream.FileBinary).%New()
write file.LinkToPath("C:\temp\test.csv")
write file.Size

Get number of lines:

set file=##class(%Stream.FileBinary).%New()
write file.LinkToPath("C:\temp\test.csv")
while 'file.AtEnd {
    do file.ReadLine()
    set linecount=$i(linecount)
write linecount

Hi Kevin,

This can be achieved by applying a dynamic filter spec to your cube/subject area. This can be done within the %OnGetFilterSpec method. Below you will find a sample that can be used against the HOLEFOODS Sample:

ClassMethod %OnGetFilterSpec(pFilterSpec As %String) As %String
Set pFilterSpec=""
If $USERNAME="Peter" {
Set pFilterSpec="[PRODUCT].[P1].[PRODUCT CATEGORY].&[Candy]"
ElseIf $USERNAME="Kevin" {
Set pFilterSpec="[PRODUCT].[P1].[PRODUCT CATEGORY].&[Pasta]"
Quit pFilterSpec

In this sample, when I log in, I will only see data related to Candy sales. When you log in, you will only see data related to Pasta sales. If anyone else logs in, they will see all categories.

Subject Areas are typically used on top of cubes when you want to filter the data like this. You can also do this directly on the cube, but it is easier to create multiple subject areas with different criteria if you stick to only using Subject Areas for this.

The logic and specs can be more complex if needed. I usually go to Analyzer and put together the necessary criteria and use the generated MDX directly or as a guide for my filter spec.


Hi Semen,

You can accomplish this using Pivot Variables + Calculated Members.

You will need to define a pivot variable named "CommonDate" (or whatever, we will use "CommonDate" for this example). This Pivot Variable will contain values like "65211". The Patients Cube in SAMPLES contains an example YEAR Pivot Variable.

You will then define two calculated members:

1) Start Date = "[StartDate].[H1].[StartDay].&[$variable.CommonDate]"

2) End Date = "[EndDate].[H1].[EndDay].&[$variable.CommonDate]"

You can then create an "Apply Pivot Variable" control in your dashboard pointing to the "CommonDate" pivot variable. This date will then be applied to both dimensions even though they have different names.