Exception when using a HardMediumSoftScore in a constraint in OptaPlanner - optaplanner

I am trying to use a HardMediumSoftScore in a constraint but I get the following exception:
java.lang.IllegalArgumentException: The constraintWeight (1hard/0medium/0soft) of class (class org.optaplanner.core.api.score.buildin.hardmediumsoft.HardMediumSoftScore) for constraintPackage (xxx) and constraintName (xxx) must be of the scoreClass (class org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore).
I cannot see anything in the documentation as to why I cannot use a medium score, or that I need to do anything different over using a hard or soft score.
I have the same problem using v8.9.1-FINAL and v8.10.0-FINAL.
Any ideas? Thanks in advance.

Some part of your planning domain will contain a reference to HardSoftScore. From this exception message, which is coming from constraints, I'm guessing that your planning solution is using HardSoftScore and not HardMediumSoftScore.
You are free to use either, but you need to consistently use one or the other.

Related

How to get deeply nested errors to get to my REST API?

First, some background:
I have a Company model, a Project model and a Task model. A Project belongs to a company and a Task belongs_to a Project.
The Project model holds several attributes: company_id, date. These attributes uniquely identify a project
I am letting the users create a task by API by POSTing to a URL that contains the details necessary to identify the Project. For example:
POST /projects/<comnpany_name>/<date>/tasks/
In order to make life easier for the users, in case there is no project with the given details, I'd like to create the project on the fly by the given details, and then to create the task and assign it to the project.
...And my problem is:
When there is a problem to create the project, let's say that the company name is not valid, what is the right way to return the error message and communicate to the user?
I'll explain what I mean: I added a create_by_name_and_company_name method to the Project:
def self.create_by_name_and_company_name(name, company_name)
if company = Company.find_by_name(company_name)
project = Project.create(company_id: company.id,
name: name)
else # cannot create this project, trying to communicate the error
project = Project.new(name: name)
project.errors.add(:company, 'must have a valid name')
end
company
end
I was hoping that by returning an unsaved Company object, with errors set, will be a good way communicate the error (This is similar to how rails work when there's a validation error).
The problem is that when calling valid? on the company object, it removed the error I wrote there and adds the regular validation errors (in this case, company can't be blank).
And a bonus question...
And there is a conceptual problem as well: since I'm creating a model by providing parameters that are being used to create the actual attributes, they doesn't always map nicely to the errors[:attr] hash. In this case it is not so bad and I'm using the company field for the company name parameter, but I guess this can get messier when the parameters provided to the create method are less similar to the model attributes.
So what is the preferred approach to tackle that problem? Is there something basically wrong with that approach? if so, what is the preferred approach?
About overriding the default rails validation error message, you need to write your validation constraint like this:
validates_presence_of :name, :message => "must be a valid name"
I figure that it is best to avoid such nesting and stick to a shallower API.

How to check unique constraint violation in nHibernate and DDD before saving?

I've got an Account model object and a UNIQUE constraint on the account's Name. In Domain Driven Design, using nHibernate, how should I check for the name's unicity before inserting or updating an entity?
I don't want to rely on a nHibernate exception to catch the error. I'd like to return a prettier error message to my user than the obscure could not execute batch command.[SQL: SQL not available]
In the question Where should I put a unique check in DDD?, someone suggested using a Specification like so.
Account accountA = _accountRepository.Get(123);
Account accountB = _accountRepository.Get(456);
accountA.Name = accountB.Name;
ISpecification<Account> spec = new Domain.Specifications.UniqueNameSpecification(_accountRepository);
if (spec.IsSatisfiedBy(accountObjA) == false) {
throw new Domain.UnicityException("A duplicate Account name was found");
}
with the Specification code as:
public bool IsSatisfiedBy(Account obj)
{
Account other = _accountRepository.GetAccountByName(obj.Name);
return (other == null);
}
This works for inserts, but not when doing an update because. I tried changing the code to:
public bool IsSatisfiedBy(Account obj)
{
Account other = _accountRepository.GetAccountByName(obj.Name);
if (obj == null) { // nothing in DB
return true;
}
else { // must be the same object.
return other.Equals(obj);
}
}
The problem is that nHibernate will issue an update to the database when it executes GetAccountByName() to recover a possible duplicate...
return session.QueryOver<Account>().Where(x => x.Name == accntName).SingleOrDefault();
So, what should I do? Is the Specification not the right way to do it?
Thanks for your thoughts!
I'm not a fan of the specification pattern for data access, it always seems like jumping hoops to get anything done.
However, what you've suggested, which really just boils down to:
Check if it already exists.
Add if it doesn't; Show user-friendly message if it does.
... is pretty much the easiest way to get it done.
Relying on database exceptions is the other way of doing it, if your database and it's .NET client gracefully propagates the table & column(s) that were infringing the unique constraint. I believe most drivers don't do so (??), as they just throw a generic ConstraintException that says "Constraint XYZ was violated on table ABC". You can of course have a convention on your unique constraint naming to say something like UK_MyTable_MyColumn and do string magic to pull the table & column names out.
NHibernate has a ISQLExceptionConverter that you can plug into the Configuration object when you set NHibernate up. Inside this, you get exposed to the exception from the .NET data client. You can use that exception to extract the table & columns (using the constraint name perhaps?) and throw a new Exception with a user friendly message.
Using the database exception way is more performant and you can push a lot of the detecting-unique-constraint-violation code to the infrastructure layer, as opposed to handling each one case by case.
Another thing worth pointing out with the query-first-then-add method is that to be completely transaction safe, you need to escalate the transaction level to serializable (which gives the worst concurrency) to be totally bullet proof. Whether you need to be totally bullet proof or not, depends on your application needs.
You need to handle it with Session.FlushMode mode to set to FlushMode.Commit and use transaction to rollback if at all update fired.

Hector API - Create Column Family - key validation class

Hey guys I am trying to load a schema into a Cassandra 0.8.2 database via Hector.
I want to add a column family (in a particular keyspace) & specify its name, comparator type, key validation class, and default validation class via Hector.
I've looked through the documentation here:
https://github.com/rantav/hector/blob/master/core/src/main/java/me/prettyprint/hector/api/factory/HFactory.java
for the function that to do this, but it seems I must have the Column Family already created (via the Cassandra CLI) to specify the default validation class, & key validation class when creating the Column Family via the CLI. Am I correct in this assumption? Am I missing any methods? Is it possible to alter the default validation class & key validation class of a Cassandra column family via Hector?
You can do that with hector. There is an example in CassandraClusterTest where you can see new column families being created with the validation class set. There are methods on BasicColumnFamilyDefinition to set the key validation class and comparator as well.

JPA & Ebean ORM: Empty collection is not empty

I've started switching over a project from hand-written JDBC ORM code to Ebeans. So far it's been great; Ebeans is light and easy to use.
However, I have run into a crippling issue: when retrieving a one-to-many list which should be empty there is actually one element in it. This element looks to be some kind of proxy object which has all null fields, so it breaks code which loops through the collection.
I've included abbreviated definitions here:
#Entity
class Store {
...
#OneToMany(mappedBy="store",cascade=CascadeType.ALL,fetch=FetchType.LAZY)
List<StoreAlbum> storeAlbums = new LinkedList<StoreAlbum>();
}
#Entity
class StoreAlbum {
...
#ManyToOne(optional=false,fetch=FetchType.EAGER)
#JoinColumn(name="store_id",nullable=false)
Store store;
}
The ... are where all the standard getters and setters are. The retrieval code looks like this:
Store s = server.find(Store.class)
.where()
.eq("store_id",4)
.findUnique();
Assert.assertEquals("Sprint",s.getStoreName());
Assert.assertEquals(0, s.getStoreAlbums().size());
The database is known to contain a 'store' row for "Sprint", and the 'store_album' table does not contain any rows for that store.
The JUnit test fails on the second assertion. It finds a list with 1 element in it, which is some kind of broken StoreAlbum object. The debugger shows the object as being of the type "com.lwm.catalogfeed.domain.StoreAlbum$$EntityBean$test#1a5e68a" with null values for all the fields which are declared as nullable=false (and optional=false).
Am I missing something here?
Thought I'd post an update on this... I ended up giving up on EBeans and instead switched the implementation over to use MyBatis. MyBatis is fantastic; the manual is easy to read and thorough. MyBatis does what you expect it to do. I got it up and running in no time.
EBeans didn't appear to detect that the join for the associated collection resulted in a bunch of null ids, but MyBatis handled this scenario cleanly.
I ran into the same issue and was able to solve it by adding an identity column to the secondary table (StoreAlbum). I did not investigate the cause but I suppose Ebean needs a primary key on the table in these kind of situations.

Problem with RavenDB 'Hello World' tutorial

I am going through the RavenDB tutorial on the RavenDb.net website.
It was going fine until I got to the code block for creating an index.
This code segment is direct from RavenDB.Net website.
store.DatabaseCommands.PutIndex("OrdersContainingProduct", new IndexDefinition<Order>
{
Map = orders => from order in orders
from line in order.OrderLines
select new { line.ProductId }
});
I get an error on compile: "The non-generic type 'Raven.Database.Indexing.IndexDefinition' cannot be used with type arguments."
If IndexDefinition is non-generic, why is it used as generic in the sample code? Where is the disconnect?
Thank you for your time
Jim
Depending on your using statements you may be referencing the wrong IndexDefinition class (from another Raven assembly). Try adding this to the beginning of your file:
using Raven.Client.Indexes;
You might need to remove other using statements as well. I guess this is one reason why Microsoft recommends using unique names for classes even in the presence of namespaces.