I am using RedHat drools DMN capability. I have set up a 'DMNRuntimeEventListener' in order to collect information about the decision table that has just run. In that event listener there is a callback method afterEvaluateDecisionTable which is called. That method receives a AfterEvaluateDecisionTableEvent object. That object does not provide a pointer to the DecisionTable that it just executed.
Instead, that object provides (1) the name of the decision node, and (2) the name of the decision table. This is a little odd because the DecisionTable object does not have a name. It has an id, and a label. But it does not have a getName() method or anything that I can find related to that.
I have the DMNModel object for the model that is being executed. From that, it is easy to find the DecisionNode by name, and the name given works. If the entire decision node is a decision table, then I don't need the decision table name, and everything works fine.
But DMN allows you to nest decision tables with other expression structures, such as a Context object. Context objects can be nested within other Context objects. So the decision node can be an elaborate tree with multiple DecisionTable objects within it. In this case, I need to find the decision table by name.
I can iterate through the tree of children, and occasionally I find objects that are in fact instanceof DecisionTable objects. OK, all I need to do is to find the name of that decision table.
getId() returns a GUID and does not match the name given
getLabel() returns a null
getIdentifierString() returns the same as getId()
I was pointed to this example code for getting a name:
public static String nameOrIDOfTable(DecisionTable sourceDT) {
if (sourceDT.getOutputLabel() != null && !sourceDT.getOutputLabel().isEmpty()) {
return sourceDT.getOutputLabel();
} else if (sourceDT.getParent() instanceof NamedElement) { // DT is decision logic of Decision, and similar cases.
return ((NamedElement) sourceDT.getParent()).getName();
} else if (sourceDT.getParent() instanceof FunctionDefinition && sourceDT.getParent().getParent() instanceof NamedElement) { // DT is decision logic of BKM.
return ((NamedElement) sourceDT.getParent().getParent()).getName();
} else {
return new StringBuilder("[ID: ").append(sourceDT.getId()).append("]").toString();
}
}
This suggests looking at the following and here at the values that I get:
getOutputLabel() is null
parent (ContextEntry) is not a NamedElement and does not have a getName() method
parent of the parent (Context) is not a NamedElement and does not have a getName() method
So this method would generate a name for the decision table, but it does not match the name I have been given by the listener. No method provides the name of the decision table (feature request: it would be really nice if the listener callback just provided a link to the DecisionTable object)
So then I start looking into the drools source to figure out how the evaluation code finds the name. What I find is that the name is PASSED IN to the evaluation method, so the name of the decision table depends on the method that calls for evaluation. I would have to analyze all the code that calls for evaluation, in order to determine what this value for decisionTableName means, because it seems to mean different things depending on who is calling for the evaluation.
Can anyone suggest a CORRECT way to find the name of the decision table that will always correspond to the name that the listener callback has provided?
The most appropriate way for your real use-case (correlate AfterEvaluateDecisionTableEvent with the "xml" DecisionTable element) would be to go via element ID.
To locate a DecisionTable in a given DMNModel, you can use something similar to this one-liner:
public static DecisionTable locateDTbyId(DMNModel dmnModel, String id) {
return dmnModel.getDefinitions()
.findAllChildren(DecisionTable.class)
.stream().filter(d -> d.getId().equals(id))
.findFirst().orElseThrow(IllegalStateException::new);
}
as for the listener events for the Decision Table before/after to be augmented with the decision table ID, PR is submitted, ref https://github.com/kiegroup/drools/pull/4860
This would align, for instance, to ContextEntry event logic as well (there again ID are used).
Thanks for having reported the gap, for feature request you can follow the instruction in https://www.drools.org/community/getHelp.html
Related
I know that MongoDb C# driver doesn't support projections so I searched a little bit and I found that many people uses a mongoCursor to perform such queries, I'm trying to select only specific fields and my code is the following:
public T GetSingle<T>(Expression<Func<T, bool>> criteria,params Expression<Func<T, object>>[] fields) where T : class
{
Collection = GetCollection<T>();
return Collection.FindAs<T>(Query<T>.Where(criteria)).SetFields(Fields<T>.Include(fields)).SetLimit(1).SingleOrDefault();
}
I got and custom repository for users on top of that:
public User GetByEmail(string mail, params Expression<Func<User, object>>[] fields)
{
return GetSingle<User>(x=>x.Email==mail,fields);
}
this is the usage:
_repository.GetByEmail(email, x=>x.Id,x=>x.DisplayName,x=>x.ProfilePicture)
but I'm getting the fields included in the parameter but also all the Enums,dates and Boolean values that are part of the class User, the values that are string and not included in the field list are null so that's fine
what can I do to avoid that?
By using SetFields, you can specify what goes through the wire. However, you're still asking the driver to return hydrated objects of type T, User in this case.
Now, similar to say an int, enum and boolean are value types, so their value can't be null. So this is strictly a C#-problem: there is simply no value for these properties to indicate that they don't exist. Instead, they assume a default value (e.g. false for bool and 0 for numeric types). A string, on the other hand, is a reference type so it can be null.
Strategies
Make the properties nullable You can use nullable fields in your models, e.g.:
class User {
public bool? GetMailNotifications { get; set; }
}
That way, the value type can have one of its valid values or be null. This can, however, be clumsy to work with because you'll have to do null checks and use myUser.GetMailNotifications.Value or the myUser.GetMailNotifications.GetValueOrDefault helper whenever you want to access the property.
Simply include the fields instead this doesn't answer the question of how to it, but there are at least three good reasons why it's a good idea to include them:
When passing a User object around, it's desirable that the object is in a valid state. Otherwise, you might pass a partially hydrated object to a method which passes it further and at some point, someone attempts an operation that doesn't make sense because the object is incomplete
It's easier to use
The performance benefit is negligible, unless you're embedding huge arrays which I would suggest to refrain from anyway and which isn't the case here.
So the question is: why do you want to make all the effort of excluding certain fields?
I am writing an application which uses ORMLite to connect to a back-end database. Since the application will be run over VPN I am trying to minimize database calls.
In order to minimize database calls I have created a set of classes to wrap the values for each field. Each wrapper class stores the original value returned from the database and also a current value. This allows things like reverting to the original value, or checking whether the value is dirty (ie. only update the database if one or more fields are dirty).
The implication of this regarding ORMLite is that ORMLite never returns a null value when it queries the database (even if the database returns null). If there is a null value in the database it returns a fully initialized "wrapper" with the currentValue and originalValue variables set to null.
It seems that the right place to do this is in a custom persister such as (where StatefulIntegerProperty is the wrapper for the Integer):
public class StatefulIntegerPersister extends BaseDataType {
... misc. other code
#Override
public Object resultToSqlArg(FieldType fieldType, DatabaseResults results, int columnPos) throws SQLException {
Integer result = results.getInt(columnPos);
return new StatefulIntegerProperty((results.wasNull(columnPos)) ? null : result);
}
#Override
public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) throws SQLException {
return sqlArg;
}
#Override
public Object javaToSqlArg(FieldType fieldType, Object obj) throws SQLException {
return ((StatefulIntegerProperty)obj).getCurrentValue();
}
#Override
public boolean isStreamType() {
return true; // this is a hack to work around ORMLite setting the value to null in the FieldType.resultToJava function
}
}
I have three questions:
Is this the correct approach?
In the ORMLite FieldType.resultToJava function it seems to do a null check and will replace my wrapper with null if the database returned null. Right now I am getting past this by overriding the isStreamType method in the persister to return true. Is this the best approach, and will I find later an unintended negative side effect?
What is the difference between the resultToSqlArg and sqlArgToJava methods in a custom persister, and specifically, which one of these should I use to wrap the value returned from the DB, and then what should I be doing in the other?
Is this the correct approach?
I don't understand why anything that you are doing here minimizes database calls. Can you start a discussion on the users' mailing list?
Right now you are overriding the resultToSqlArg(...) method when I think you want the sqlArgToJava(...). See below.
Right now I am getting past this by overriding the isStreamType method in the persister to return true. Is this the best approach...
Hrm. If it works then fine but it seems dangerous to use this setting in this manner. If I changed the behavior of the isStreamType() method then this may break your code. At the very least you should have unit tests to confirm this behavior that will break if you upgrade ORMLite.
That said, there is good handling in the code specifically around null values if isStreamType() is true.
What is the difference between the resultToSqlArg and sqlArgToJava...
I've fleshed out the javadocs for these.
resultToSqlArg takes the object from the SQL results and turns it into a java-object suitable to be an argument to SQL commands. For example, if you have a date-long type, this will extract a Long value from the database results.
sqlArgToJava takes the sql-arg value and converts it into our Java field. For example, if you have a date-long type, this will take a Long value and convert it into a Date which matches the entity field.
I think you should override the sqlArgToJava and not the resultToSqlArg.
I have an simple object that has a name
public class Foo {
private String name
}
Each user on the site may have up to 10 Foo's associated with them. Within this context, when a new Foo is created, I would like to validate that there isn't another foo associated with the same user that already exists.
I could Create a custom Bean Validator But annotations require the paramaeters to be defined during compilation. How would I then pass across the names of the existing Foos?
As suggested in various places, I could use EL expressions as an alternative way to pick up the data. This feels like using a sledgehammer to crack a nut. It also brings in a whole bunch of potential issues to consider least of all being ease of testing.
I could do class-wide validation using a boolean field
#AssertTrue(message="Name already exists")
public boolean isNameUnique() {
return (existingNames.contains(name));
}
But the validation message would not show up next to the name field. It is a cosmetic issue and this can be a backup plan. However, its not ideal.
Which brings me to the question:
Is there a simple way to write a Bean Validator that can check the value against a collection of values at the field level and meet the following restrictions ?
Previous values determined at runtime
Not using things like EL expressions
Field level validation instead of class level.
EDIT in reponse to Hardy:
The Foo class is an entity persisted within a database. They are picked up and used through a DAO interface.
I could loop through the entities but that means plugging the DAO into the validator and not to mention that the I would need to write the same thing again if I have another class that too has this constraint.
It would help to see how you want to use the Foo class. Can you extend your example code? Are they kept in a list of Foo instances. A custom constraint seems to be a good fit. Why do you need to pass any parameters to the constraints. I would just iterate over the foos and check whether the names are unique.
This is directly out of the Zend Quick Start guide. My question is: why would you need the setDbTable() method when the getDbTable() method assigns a default Zend_Db_Table object? If you know this mapper uses a particular table, why even offer the possibility of potentially using the "wrong" table via setDbTable()? What flexibility do you gain by being able to set the table if the rest of the code (find(), fetchAll() etc.) is specific to Guestbook?
class Application_Model_GuestbookMapper
{
protected $_dbTable;
public function setDbTable($dbTable)
{
if (is_string($dbTable)) {
$dbTable = new $dbTable();
}
if (!$dbTable instanceof Zend_Db_Table_Abstract) {
throw new Exception('Invalid table data gateway provided');
}
$this->_dbTable = $dbTable;
return $this;
}
public function getDbTable()
{
if (null === $this->_dbTable) {
$this->setDbTable('Application_Model_DbTable_Guestbook');
}
return $this->_dbTable;
}
... GUESTBOOK SPECIFIC CODE ...
}
class Application_Model_DbTable_Guestbook extends Zend_Db_Table_Abstract
{
protected $_name = 'guestbook_table';
}
Phil is correct, this is known as lazy-loading design pattern. I just implemented this pattern in a recent project, because of these benefits:
When I call on getMember() method, I will get a return value, regardless if it has been set before or not. This is great for method chaining: $this->getCar()->getTires()->getSize();
This pattern offers flexibility in that outside calling code is still able to set member values: $myClass->setCar(new Car());
-- EDIT --
Use caution when implementing the lazy-loading design pattern. If your objects are not properly hydrated, a query will be issued for every piece of data which is NOT available. The best thing to do is tail your db query log, during the dev phase, to ensure the number and type of queries are what you expect. A project I was working on was issuing over 27 queries for a "detail" page, and I had no idea until I saw the queries.
This method is called lazy-loading. It allows a property to remain null until requested unless it is set earlier.
One use for setDbTable() would be testing. This way you could set a mock DB table or something like that.
One addition: if setDbTable() is solely for lazy-loading, wouldn't it make more sense to make it private? That way it will avoid accidental assignment and to wrong table as originally mentioned by Sam.
Should we be compromising the design for the sake of testability?
I'm aware there is an AssociationChanged event, however, this event fires after the association is made. There is no AssociationChanging event. So, if I want to throw an exception for some validation reason, how do I do this and get back to my original value?
Also, I would like to default values for my entity based on information from other entities but do this only when I know the entitiy is instanced for insertion into the database. How do I tell the difference between that and the object getting instanced because it is about to be populated based on existing data? Am I supposed to know? Is that considiered business logic that should be outside of my entity business logic?
If that's the case, then should I be designing controller classes to wrap all these entities? My concern is that if I deliver back an entity, I want the client to get access to the properties, but I want to retain tight control over validations on how they are set, defaulted, etc. Every example I've seen references context, which is outside of my enity partial class validation, right?
BTW, I looked at the EFPocoAdapter and for the life of me cannot determine how to populate lists of from within my POCO class... anyone know how I get to the context from a EFPoco Class?
This is in reply to a comment I left. Hopefully this answers your question, Shimmy. Just comment, and I will shorten it or remove it if it doesn't answer your question.
You will need both INotifyPropertyChanging and INotifyPropertyChanged interfaces to be implemented on your class (unless it is something like an entity framework object, which I believe implements these internally).
And before you set a value to this property, you will need to raise NotifyPropertyChanging.PropertyChanging event, using the name of the property in PropertyChangingEventArgs constructor.
And after you set this value you need to raise NofityPropertyChanged.PropertyChanged event, again using the name of the property this is being raised in PropertyChangedEventArgs constructor.
Then you have to handle the PropertyChanging and PropertyChanged events. In the PropertyChanging event, you need to cache the value. In the PropertyChanged event, you can compare and throw an exception.
To get the property from PropertyChanging/PropertyChanged event args, you need to use relfection.
// PropertyName is the key, and the PropertyValue is the value.
Dictionary <string, object> propertyDict = new Dictionary<object, object>();
// Convert this function prototype to C# from VBNet. I like how Handles is descriptive.
Public Sub PropertyChanging(sender As object, e As PropertyChangingEventArgs) Handles Foo.PropertyChanging
{
if (sender == null || preventRecursion)
{
return;
} // End if
Type senderType = sender.GetType();
PropertyInfo info = senderType.GetProperty(e.PropertyName);
object propertyValue = info.GetValue(sender, null);
// Change this so it checks if e.PropertyName already exists.
propertyDict.Add(e.PropertyName, propertyValue);
} // End PropertyChanging() Event
// Convert this function prototype to C# from VBNet. I like how Handles is descriptive.
Public Sub PropertyChanged(sender As object, e As PropertyChangedEventArgs) Handles Foo.PropertyChanged
{
if (sender == null || preventRecursion)
{
return;
} // End if
Type senderType = sender.GetType();
PropertyInfo info = senderType.GetProperty(e.PropertyName);
object propertyValue = info.GetValue(sender, null);
// Change this so it makes sure e.PropertyName exists.
object oldValue = propertyDict(e.PropertyName);
object newValue = propertyValue;
// No longer needed.
propertyDict.Remove(e.PropertyName);
if (/* some condition */)
{
try {
preventRecursion = true;
info.SetValue(oldValue, null);
Throw New Exception();
} finally {
preventRecursion = false;
} // End try
} // End if
} // End PropertyChanging() Event
Notice how I am using PreventRecursion, which is a boolean I forgot to add above these methods? When you reset the property back to its previous value, these events will be recalled.
tl;dr
Now you could derive a single event which inherits from INotifyPropertyChanged, but uses an argument which holds an Object representing the previous value as well as the Property Name. And that would reduce the number of events being fired down to one, have similar functionality, and have backwards compatibility with INotifyPropertyChanged.
But if you want to handle anything before the property gets set (say the property does an irreversible change or you need to setup other properties before setting that variable, otherwise an exception will be thrown) you won't be able to do that.
Overall, this method is a very old way of doing things. I would take Poker Villian's answer and have invalid data able to be entered. But disallow saving to a database.
Entity Framework has some excellent code towards validation. You add validation to your properties via attributes. And then it takes care of the work of processing those attributes. Then you can make a property called IsValid, which calls Entity Framework specific validation. It also distinguishes both field errors (like typing in the wrong characters or having a string too long), and class errors (like having missing data or conflicting keys).
Then you can bind IsValid to controls validation, and they will display a red bubble while invalid data is entered. Or you could just implement IsValid validation yourself. But If IsValid is false, SaveChanges event would need to cancel saving.
btw. The code provided will not compile and is pseudocode only (mixing vb and c#). But I believe it is much more descriptive than c# alone--showing exactly what is being handled.
Concerning your first question, I would simply implement the changes to the associations as business logic. For example, if you add a Teacher class with multiple Student, do not add students like
aTeacher.Students.Add(new Student)
instead, create a AddStudent method
public Student AddNewStudent(string name, string studentID)
{
Student s = new Student( name, studentID);
s.Teacher = this; // changes the association
return s;
}
That way you have full control on when associations are changed. Of course that what prevents another programmer from adding a student directly? On the Student side, you can set the Teacher setter to private (and change the constructor to accept a teacher or similar). On the teacher side, how to make the Students collection non-insertable? I'm not certain... maybe transforming it in a custom collection that doesn't accept inserts.
Concerning the second part of your question, you could probably use the OnVarNameChanging events. If the EntityState is 'New' then you can apply your logic that fetches the real values.
There is also an event that fires when you save changes (OnSavingChanges?) that you could use to determine which objects are new and set some values.
But maybe the simplest solution is to always set the defaults in the constructor and they will get overwritten if the data is loaded from the DB.
Good luck
Create a factory that produces instances for you depending on your need like:
getStudent(String studentName, long studentId, Teacher teacher) {
return new Student(studentName, studentId);
}
getStudentForDBInseration(String studentName, long studentId, Teacher teacher) {
Student student = getStudent(studentName, studentId);
student = teacher;
//some entity frameworks need the student to be in the teachers student list
//so you might need to add the student to the teachers student list
teacher.addStudent(student);
}
It's a serious lack not having an AssociationChanging (that inherits from CancelEventArgs) event.
It bothers me also very much, therefore I reported this to Microsoft Connect Please vote here!
And BTW, I also think this is also stupid that the PropertyChangingEventArgs doesn't inherit CancelEventArgs, since cancelling with an exception is not always the elegant solution, besides, throwing exceptions cost more performance than calling the OnPropertyChangingEvent then check for the returned e.Cancel, so does it cost less than raising the PropertyChangingEvent, which you anyway call them both.
Also an exception can be thrown at the handler anyway instead of marking e.Cancel as true, for those who insist to go the Exception way. Vote Here.
To maybe answer part of your question or expound on ADB's answer you can user ObjectStateManager.GetObjectStateEntry to find the state of the entities and write your custom default logic.
SaveChanges is the method on the context that you can use, or SavingChanges is the event that occurs before SaveChanges is called.
You can override SaveChanges and only call base.SaveChanges if you don't want to abort the change
There is also a ObjectMaterialized event for the context.
Between the two you can stick all your validation and creation code in one location, which may be appropriate if they are complex and include values of other objects etc..