I'm trying to figure out how to update a relationship using a list of foriegn keys.
Take for example the standard parent/children relationship from the SQLAlchemy documentation:
class Parent(Base):
__tablename__ = "parent_table"
id: Mapped[int] = mapped_column(primary_key=True)
children: Mapped[list["Child"]] = relationship(back_populates="parent")
class Child(Base):
__tablename__ = "child_table"
id: Mapped[int] = mapped_column(primary_key=True)
parent_id: Mapped[int] = mapped_column(ForeignKey("parent_table.id"), nullable=True)
parent: Mapped["Parent"] = relationship(back_populates="children")
The normal relationship modelling means that if I want to update the list of children from the parent I need to have all of those child objects. Instead I'd like to have a property on the Parent class that is the id's of the ascociated Child classes but can be updated as well.
I've seen this answer: how to access list of keys for a relationship in SQLAlchemy? which gives the "read" side of the equation, but how can I write an efficient setter to do the other half?
Note: The children in my scenario already exist. I suspect I need to use the update_expression function in order to build a sql query that will go and look for the existing children and link them accross. But I'm not sure if that's right...
This is what I've got so far.
#hybrid_property
def child_ids(self) -> List[uuid.UUID]:
return [child.id for child in self.children]
#child_ids.expression
def child_ids(self):
select([Child.id]).where(
Child.parent_id == self.id
)
#child_ids.setter
def child_ids(self, value):
# What here?
pass
For completeness, I'm specifically asking how to do this in the Model using properties/hybrid_properties.
This seems to work but I'm not sure how reliable it will be with a lot of simultaneous requests to set child_ids. If it is a big deal you might get a row lock on the parent to synchronize calls to set child_ids.
delete and insert differences between value and self.children
you need to set delete-orphan cascade or else Child objects end up with Child(id=5, parent_id=None) when using self.children.remove(child)
class Parent(Base):
__tablename__ = 'parents'
id = Column(Integer, primary_key=True)
#hybrid_property
def child_ids(self):
return [child.id for child in self.children]
#child_ids.expression
def child_ids(self):
return select([Child.id]).where(
Child.parent_id == self.id
)
#child_ids.setter
def child_ids(self, value):
"""
Sync children with given children ids.
value: list[int]
List of children ids.
"""
# Child ids in value found in self.children.
found_child_ids = set()
# Childs in self.children whose id is not in value.
to_delete = set()
for child in self.children:
if child.id not in value:
to_delete.add(child)
else:
found_child_ids.add(child.id)
# Delete children not in value.
for child in to_delete:
# This only deletes the Child object because we have delete-orphan cascade set.
self.children.remove(child)
# Create children with child ids in value that were not found in self.children.
for child_id in (set(value) - found_child_ids):
self.children.append(Child(id=child_id, parent_id=self.id))
children = relationship('Child', back_populates="parent",
# Need this to delete orphaned children.
cascade="all, delete-orphan")
class Child(Base):
__tablename__ = 'childs'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parents.id'))
parent = relationship('Parent', back_populates="children")
metadata.create_all(engine)
with Session(engine) as session, session.begin():
p1 = Parent()
session.add(p1)
with Session(engine) as session:
p1 = session.get(Parent, 1)
# Add 1, 5
p1.child_ids = [1, 5]
session.commit()
# Add 2, Remove 1, Leave 5
p1.child_ids = [2, 5]
session.commit()
# Remove 2, Remove 5
p1.child_ids = []
session.commit()
Echo after create_all
2023-01-17 21:35:51,060 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2023-01-17 21:35:51,064 INFO sqlalchemy.engine.Engine INSERT INTO parents DEFAULT VALUES RETURNING parents.id
2023-01-17 21:35:51,065 INFO sqlalchemy.engine.Engine [generated in 0.00058s] {}
2023-01-17 21:35:51,067 INFO sqlalchemy.engine.Engine COMMIT
2023-01-17 21:35:51,104 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2023-01-17 21:35:51,106 INFO sqlalchemy.engine.Engine SELECT parents.id AS parents_id
FROM parents
WHERE parents.id = %(pk_1)s
2023-01-17 21:35:51,106 INFO sqlalchemy.engine.Engine [generated in 0.00021s] {'pk_1': 1}
2023-01-17 21:35:51,109 INFO sqlalchemy.engine.Engine SELECT childs.id AS childs_id, childs.parent_id AS childs_parent_id
FROM childs
WHERE %(param_1)s = childs.parent_id
2023-01-17 21:35:51,110 INFO sqlalchemy.engine.Engine [generated in 0.00017s] {'param_1': 1}
2023-01-17 21:35:51,112 INFO sqlalchemy.engine.Engine INSERT INTO childs (id, parent_id) VALUES (%(id)s, %(parent_id)s)
2023-01-17 21:35:51,112 INFO sqlalchemy.engine.Engine [generated in 0.00017s] ({'id': 1, 'parent_id': 1}, {'id': 5, 'parent_id': 1})
2023-01-17 21:35:51,114 INFO sqlalchemy.engine.Engine COMMIT
2023-01-17 21:35:51,163 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2023-01-17 21:35:51,165 INFO sqlalchemy.engine.Engine SELECT parents.id AS parents_id
FROM parents
WHERE parents.id = %(pk_1)s
2023-01-17 21:35:51,165 INFO sqlalchemy.engine.Engine [generated in 0.00025s] {'pk_1': 1}
2023-01-17 21:35:51,166 INFO sqlalchemy.engine.Engine SELECT childs.id AS childs_id, childs.parent_id AS childs_parent_id
FROM childs
WHERE %(param_1)s = childs.parent_id
2023-01-17 21:35:51,166 INFO sqlalchemy.engine.Engine [cached since 0.05671s ago] {'param_1': 1}
2023-01-17 21:35:51,168 INFO sqlalchemy.engine.Engine INSERT INTO childs (id, parent_id) VALUES (%(id)s, %(parent_id)s)
2023-01-17 21:35:51,168 INFO sqlalchemy.engine.Engine [generated in 0.00017s] {'id': 2, 'parent_id': 1}
2023-01-17 21:35:51,170 INFO sqlalchemy.engine.Engine DELETE FROM childs WHERE childs.id = %(id)s
2023-01-17 21:35:51,170 INFO sqlalchemy.engine.Engine [generated in 0.00015s] {'id': 1}
2023-01-17 21:35:51,170 INFO sqlalchemy.engine.Engine COMMIT
2023-01-17 21:35:51,204 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2023-01-17 21:35:51,206 INFO sqlalchemy.engine.Engine SELECT parents.id AS parents_id
FROM parents
WHERE parents.id = %(pk_1)s
2023-01-17 21:35:51,206 INFO sqlalchemy.engine.Engine [cached since 0.04138s ago] {'pk_1': 1}
2023-01-17 21:35:51,208 INFO sqlalchemy.engine.Engine SELECT childs.id AS childs_id, childs.parent_id AS childs_parent_id
FROM childs
WHERE %(param_1)s = childs.parent_id
2023-01-17 21:35:51,209 INFO sqlalchemy.engine.Engine [cached since 0.09924s ago] {'param_1': 1}
2023-01-17 21:35:51,211 INFO sqlalchemy.engine.Engine DELETE FROM childs WHERE childs.id = %(id)s
2023-01-17 21:35:51,211 INFO sqlalchemy.engine.Engine [generated in 0.00025s] ({'id': 2}, {'id': 5})
2023-01-17 21:35:51,212 INFO sqlalchemy.engine.Engine COMMIT
Background
I have a MySQL table with a json field. That field stores a array of json objects.
The order is not always the same, so i need to get the path to a key for updating operations.
Entity | ID, jsonField |
Entity | 1, [{clazz:'health', hp:'100'},{...},{...}] // Health the first index
Entity | 2, [{...},{...},{clazz:'health', hp:'25'}] // Health at the last index
The question
How do i get the path to the .hp field for every single entity in order to update its value ? Or... a bit more precious, how do we set the .hp field to, lets say 100, in every entity jsonField array, regardless of its position ?
You can use a recursive CTE to find the index for the hp key in the array (if it exists), and then use that result to make the update:
with recursive cte(id, js, ind, f) as (
select e.id, e.jsonfield, 0, json_extract(e.jsonfield, '$[0].hp') is not null from entities e
union all
select c.id, c.js, c.ind+1, json_extract(c.js, concat('$[', c.ind+1, '].hp')) is not null from cte c where not c.f and c.ind+1 < json_length(c.js)
),
inds(id, ind) as (select id, ind from cte where f)
update entities e join inds i on e.id = i.id set e.jsonfield = json_set(e.jsonfield, concat('$[', i.ind, '].hp'), '100');
select * from entites;
Output:
entity
id
jsonfield
entity
1
[{"hp": "100", "clazz": "health"}, {"x": "1"}, {"y": "2"}]
entity
2
[{"x": "1"}, {"y": "2"}, {"hp": "100", "clazz": "health"}]
I have not seen this error before, I tried inserting these to my database table
INSERT courses
SET startTime= '30-Dec-2020 09:00:00', exam_catID = 2, courseTitle = 'Test course',
courseCode = 'Tcs299', duration = 3
courses Atributes
startTime (Varchar)
exam_catID (Int)
courseTitle (Varchar)
courseCode (Varchar)
duration (int)
Outpur Error
Fatal error: Uncaught TypeError: Argument 1 passed to PhpMyAdmin\DatabaseInterface::escapeString() must be of the type string, null given, called in C:\xampp\phpMyAdmin\libraries\classes\Tracker.php on line 149 and defined in C:\xampp\phpMyAdmin\libraries\classes\DatabaseInterface.php:2991 Stack trace: #0 C:\xampp\phpMyAdmin\libraries\classes\Tracker.php(149): PhpMyAdmin\DatabaseInterface->escapeString(NULL) #1 C:\xampp\phpMyAdmin\libraries\classes\Tracker.php(841): PhpMyAdmin\Tracker::isTracked('time_table_syst...', NULL) #2 C:\xampp\phpMyAdmin\libraries\classes\DatabaseInterface.php(345): PhpMyAdmin\Tracker::handleQuery('INSERT courses ...') #3 C:\xampp\phpMyAdmin\libraries\classes\Sql.php(958): PhpMyAdmin\DatabaseInterface->tryQuery('INSERT courses ...', 256, 1) #4 C:\xampp\phpMyAdmin\libraries\classes\Sql.php(1177): PhpMyAdmin\Sql->executeQueryAndMeasureTime('INSERT courses ...') #5 C:\xampp\phpMyAdmin\libraries\classes\Sql.php(2225): PhpMyAdmin\Sql->executeTheQuery(Array, 'INSERT courses ...', false, 'time_table_syst in C:\xampp\phpMyAdmin\libraries\classes\DatabaseInterface.php on line 2991
You should use proper insert statement. You are missing INTO clause:
INSERT into courses
SET startTime= '30-Dec-2020 09:00:00', exam_catID = 2, courseTitle = 'Test course',
courseCode = 'Tcs299', duration = 3
Or you can use the standard sql as follows:
INSERT into courses( startTime, exam_catID , courseTitle, courseCode, duration)
values ( '30-Dec-2020 09:00:00', 2, 'Test course', 'Tcs299', 3)
I am trying to convert and replicate json document stored in oracle table (source) as clob value to target database (oracle) as rdbms table using oracle goldengate :
GGSCI (ggsrv2.localdomain) 39> view params RJSON3
Replicat rjson3
DiscardFile ./dirrpt/rjson3.dsc, Purge
USERID ogg, PASSWORD oracle
Map HR.JSON_TEST_SOURCE, Target HRTRG.JSON_TEST_TARGET,
SQLEXEC (id lookup, QUERY 'SELECT json_value(jsondoc, '$.IDNumber') AS J_ID, json_value(jsondoc, '$.Description') AS J_DESCRIPTION, json_value(jsondoc, '$.DecimalNumber') AS J_DECIMAL FROM
HRTRG.JSON_TEST_SOURCE
WHERE ID = :V_ID ',
PARAMS (V_ID = ID)),
J_ID = #GETVAL(lookup.J_ID)),
J_DESCRIPTION = #GETVAL(lookup.J_DESCRIPTION)),
J_DECIMAL = #GETVAL(lookup.J_DECIMAL))
);
Error message:
2019-01-06 07:56:54 WARNING OGG-10173 (rjson3.prm) line 4 column 317: Parsing error, value "'#'" syntax error.
2019-01-06 07:56:54 WARNING OGG-10173 (rjson3.prm) line 4: Parsing error, option [sqlexec] for parameter [map] has unrecognized value "=".
2019-01-06 07:56:54 WARNING OGG-10173 (rjson3.prm) line 4: Parsing error, option [sqlexec] for parameter [map] has unrecognized value "J_ID"."
Database version 12cR2,GoldenGate version 12.3
Source Table:
SQL> desc HR.JSON_TEST_SOURCE;
Name Null? Type
------- -------- ------------
ID NOT NULL NUMBER(10)
JSONDOC CLOB
Sample data on Source table:
SQL> col JSONDOC for a55
SQL> select * from HR.JSON_TEST_SOURCE;
ID JSONDOC
---------- -------------------------------------------------------
1600 { "IDNumber" : 01,
"Description" : "I am Shanoj",
"DecimalNumber" :
1601 { "IDNumber" : 02,
"Description" : "I am Joby",
"DecimalNumber" : 1
1602 { "IDNumber" : 03,
"Description" : "I am Siriram",
"DecimalNumber"
1603 { "IDNumber" : 04,
"Description" : "No idea who I am",
"DecimalNumb
Target Table:
SQL> desc HRTRG.JSON_TEST_TARGET
Name Null? Type
-------------- -------- --------------
J_ID NOT NULL VARCHAR2(4000)
J_DESCRIPTION VARCHAR2(4000)
J_DECIMAL VARCHAR2(4000)
Looks like you may to use some adapters. Another option is to use a materialized view from target to get the JSon values as records using json_values().
I want to store the details of college courses in a (MySql) database but I'm not sure how to maintain the relationship between modules and selections.
Basically, a course can have mandatory section, group of optional modules, an options section and within each there can be selections which contain ANDs or ORs between modules.
Simple example:
A 60 credit course has a few mandatory modules which make up 40 credits. That leaves 20 credits to be selected from the group of optional modules. (Modules themselves can hold different amount of credits). Effectively; ('Mandatory module 1' AND 'Mandatory module 2'... AND'Mandatory module N') AND (40 credits from 'optional modules'),
ANDs & ORs:
When I say modules above, it could be a single module or it could be "Module x OR Module Y" i.e. in the mandatory section. (those modules would obviously have to have the same credit weight).
Or in the optional section there might be single modules or even one of the choices could be something like "module x AND module y".
Options:
The students may have to take the mandatory modules plus one of n options which may or may not contain ANDs, ORs, and mandatory & optional sections; i.e. An 'Option' has all the attributes of the overall course modules selection. The Options section would be AND'd or OR'd with other sections like mandatory or optional; i.e. mandatory modules "plus one of the following options". Effectively the options section is just 'Option 1' OR 'Option 2'... OR 'Option N'.
The problem is how do I store all of the AND and OR relationships when the operand may be another AND/OR operation or a single module, and keep track of the amount of credits allowed for each selection; e.g. "20 credits from the following:" (group of optional modules).
A very simple, first approach would be using just 4 tables:
TABLE Course
( CourseId
, Title
, TotalCredits
, ... other stuff
, PRIMARY KEY (CourseId)
) ;
TABLE Module
( ModuleId
, Description
, Hours
, Credits
, ... other stuff
, PRIMARY KEY (ModuleId)
) ;
and the combinations allowed through these 2:
TABLE Course_Module
( CourseID --- for this course
, ModuleID --- this module is allowed (optional or mandatory)
, PRIMARY KEY (CourseID, ModuleId)
, FOREIGN KEY (CourseId)
REFERENCES Course (CourseId)
, FOREIGN KEY (ModuleId)
REFERENCES Module (ModuleId)
) ;
TABLE Course_MandatoryModule
( CourseID --- for this course
, ModuleID --- this module is mandatory
, PRIMARY KEY (CourseID, ModuleId)
, FOREIGN KEY (CourseID, ModuleId)
REFERENCES Course_Module (CourseID, ModuleId)
) ;
Now, if your allowed combinations of modules and courses is more complicated, as your description suggests, instead of the Course_Module and the Course_MandatoryModule tables you could define a complex hierarchical model:
Courses:
TABLE Course --- same as previous model
( CourseId
, Title
, TotalCredits
, ... other stuff
, PRIMARY KEY (CourseId)
) ;
Modules and groups of (modules):
TABLE ModuleEntity --- the supertype for both
( ModuleEntityId --- modules and group of modules
, PRIMARY KEY (ModuleEntityId)
) ;
TABLE Module --- subtype
( ModuleId
, Description
, Hours
, Credits
, ... other stuff
, PRIMARY KEY (ModuleId)
, FOREIGN KEY (ModuleId)
REFERENCES ModuleEntity (ModuleEntityId)
) ;
TABLE ModuleGroup --- group of modules
( ModuleGroupId --- subtype of the supertype (entity)
, GroupDescription
, PRIMARY KEY (ModuleGroupId)
, FOREIGN KEY (ModuleGroupId)
REFERENCES ModuleEntity (ModuleEntityId)
) ;
and relationship (module belongs to group):
TABLE Module_in_Group
( ModuleEntityId --- this module or group
, ModuleGroupId --- is in this group
, PRIMARY KEY (ModuleEntityId, ModuleGroupID)
, FOREIGN KEY (ModuleEntityId)
REFERENCES ModuleEntity (ModuleEntityId)
, FOREIGN KEY (ModuleGroupId)
REFERENCES ModuleGroup (ModuleGroupId)
) ;
and (finally) course can have group of modules:
TABLE Course_ModuleGroup
( CourseId --- for this course
, ModuleGroupId --- this module group is allowed
, PRIMARY KEY (CourseID, ModuleGroupId)
, FOREIGN KEY (CourseId)
REFERENCES Course (CourseId)
, FOREIGN KEY (ModuleGroupId)
REFERENCES ModuleGroup (ModuleGroupId)
) ;
The design is fairly straight-forward you just need a recursive "group" table with constraints.
Course
- ID
- Title
- Credits
Course_Group
- CourseID
- GroupID
Group
- ID
- GroupID
- Description
- AtLeastNSelections
- AtLeastNCredits
Group_Module
- GroupID
- ModuleID
Module
- ID
- Title
- Credits
An example structure would be
Course: 1, "Math Major", 60
Group: 1, NULL, "Core Modules", 2, 40
Course_Group: 1, 1
Group: 2, 1, "Required (5) Core Modules", 5, 25
Course_Group: 1, 1
Group_Module: (1, 1), (1, 2), (1, 3), (1, 4), (1, 5)
Module: 1, "Calculus I", 5
Module: 2, "Calculus II", 5
Module: 3, "Calculus III", 5
Module: 4, "Stats I", 5
Module: 5, "Stats II", 5
Group: 3, 1, "Required (3) Of (N) Modules", 3, 15
Course_Group: 1, 3
Group_Module: (3, 6), (3, 7), (3, 8), (3, 9), (3, 10)
Module: 6, "Number Theory", 5
Module: 7, "Bridge Adv. Math", 5
Module: 8, "Calculus IV", 5
Module: 9, "Stats III", 5
Module: 10, "Finite Math", 5
Group: 4, NULL, "Secondary Modules", 1, 20
Course_Group: 1, 4
Group: 5, 4, "Comp. Sci.", 2, 0
Course_Group: 1, 5
Group_Module: (5, 11), (5, 12), (5, 13), (5, 14), (5, 15), (5, 16)
Module: 11, "Math in Hardware", 4
Module: 12, "Math in Software", 4
Module: 13, "Programming 101", 4
Module: 14, "Algorithms 101", 4
Module: 15, "Programming I", 5
Module: 16, "Programming II", 5
Group: 6, 4, "Physics", 0, 8
Course_Group: 1, 6
Group_Module: (6, 17), (6, 18), (6, 19), (6, 20)
Module: 17, "Physics Mechanics", 4
Module: 18, "Physics Thermodynamics", 4
Module: 19, "Physics Magnetism", 5
Module: 20, "Physics Theoretical", 5
Group: 7, 4, "Gen. Ed.", 0, 0
Course_Group: 1, 7
Group_Module: (7, 21), (7, 22), (7, 23), (7, 24)
Module: 21, "Business Writing", 3
Module: 22, "Ethics", 3
Module: 23, "Aesthetics", 3
Module: 24, "Graphic Design", 3
A quick walk through... the course "Math Major" has two groups under it "Core Modules" and "Secondary Modules". "Core Modules" requires AT LEAST 2 children AND AT LEAST 40 credits.
"Secondary Modules" requires AT LEAST 1 child AND AT LEAST 20 credits.
You can see that the constraints of the groups under "Core Modules" are more restrictive than the constraints of the groups under "Secondary Modules".
To output the example structure above would be something like.
SELECT c.Title, g.Description, m.Title FROM Course c
INNER JOIN Course_Group cg ON c.ID = cg.CourseID
INNER JOIN Group g ON cg.GroupID = g.ID
INNER JOIN Group_Module gm ON g.ID = gm.GroupID
INNER JOIN Module m ON gm.ModuleID = m.ID
WHERE c.ID = 1
ORDER BY g.GroupID, g.ID, m.Title
So if you have a course and modules you can get all the groups for the course from the Course_Group table and get which group the modules belong to from the Group_Module table. Once you have the modules in their group(s) you can check the group's constraints AtLeastNSelections AND AtLeastNCredits walking up the Group.GroupID parentage chain until you get to Group.GroupID = NULL.
You can create a recursive table structure here, wherein Options reference their parent options.
The "main" options can then be identified by querying this table for all options with "null" parents.
The "and-or" relationships can be implemented by a separate "option-set" table, where the primary key is to an "option". The option-set table's with null self-references are the "root" point for defining a course's options. From that point, you will select option-set records with parent = root. This will be the first "level" of options. Some will be mandatory, some won't. To express that, you will have to have a boolean attribute on the option-set table as a flag. Thus each option-set is defined in terms of smaller option-sets. Of course, ultimately, once you get to the bottom, your option-set's will define an actual class at some point.
I would suggest that this can much more effectively be modelled in JSON or XML, since those data structures support hierarchies in a much more expressive manner.
You can probably do something like this:
TABLE course_definition (
ID int,
num_mandatory_sections int,
mandatory_hours int,
num_optional_modules int,
optional_hours int,
);
TABLE modules (
ID int,
Description varchar(max),
hours int,
....
);
TABLE course (
Course_ID int FOREIGN KEY (course_definition.id),
module_id int FOREIGN KEY (modules.id)
);
TABLE course_module_relationship (
Course_ID int FOREIGN KEY (course_definition.id),
module_ID int foreign key (modules.id),
Requirement_flag ENUM ("MANDATORY", "OPTIONAL")
);
TABLE Student_to_course (
Student_ID int,
Course_ID int foreign key (course_definition.id)
);
TABLE Student_to_module (
Student_ID int,
Module_ID int FOREIGN KEY (module.id)
);
If you really need to be able to create group modules aka single module created from the multiple other modules then table module will need to have a flag field:
group_module boolean
and the following table should be added:
TABLE module_groupings (
group_module_ID int foreign key (module.id)
dependant_module_id int foreign key (module.id)
);
This is more of pseudo code but you get the idea. The table course and course_module_relationship will have no keys and store your relationships as they can be many to many as I understand the problem. So basically the code that will read process the selections will have to check whether or not this meets the criteria for the course_definition.
If the Mandatory section to Course is a 1-to-1 relationship you can separate your mandatory section into a separate table but you will have to analyze your data more thoroughly.
A production quality system using and/or's (like your system) that you can review for free is entlib 5.0 Security block. http://entlib.codeplex.com/
Each rule is retrieved by name to get the full expression. the patterns & practice team created their own short DSL for the expression to avoid complicating the xml structure/db structure.
this is inside the hands on labs exercise ex02 app.config. To store rules inside the database you would need to implement a custom AuthorizationRuleProvider.
R: = rolename; U: = username
<securityConfiguration defaultAuthorizationInstance="RuleProvider"
defaultSecurityCacheInstance="">
<authorizationProviders>
<add type="Microsoft.Practices.EnterpriseLibrary.Security.AuthorizationRuleProvider, Microsoft.Practices.EnterpriseLibrary.Security"
name="RuleProvider">
<rules>
<add expression="R:Employee OR R:Developer OR R:Manager" name="Raise Bug" />
<add expression="R:Manager" name="Assign Bug" />
<add expression="R:Developer OR R:Manager" name="Resolve Bug" />
</rules>
</add>
</authorizationProviders>
dev usage
public static AssignBug Create()
{
// TODO: Check Authorization
if (!SecurityHelper.Authorized(AuthRule.Assign))
{
throw new SecurityException();
}
return new AssignBug();
}
While not an immediate answer I think this provides a good example of how to implement rule-expression based systems.