uniqueness of composite id with null component - sql

I am running into problems using unique constraints.
The following combinations are allowed
A.name B.name
foo NULL
foo bar
foo bar1
foo1 bar
It should not be possible to create a new A with same name, only if it has a different B.
With the constraints below it is possible to create
A.name B.name
foo NULL
foo NULL
Because NULL seems not to have effect on unique.
Any hints how to fix this?
class A {
String name
static belongsTo = [b:B]
static constraints = {
name(unique:'b')
b(nullable:true)
}
}
class B {
String name
static hasMany = [as:A]
name(unique:true)
}

In the database structure, could you set the columns to NOT NULL DEFAULT 0 or similar, and then treat the zeros the same as you otherwise would the NULLs? Since the column is for names, there's likely to be no digits in the values anyway right?

I'm not entirely sure, but I think this will work:
name(unique:['b', 'name'])
Looking at the code for the unique constraint, it seems feasible. The constraint definitely lets you pass in a list of things to compare the uniqueness to. It calls this the uniquenessGroup. Then, when validating, it iterates over this list. Take a look starting at line 137 here: http://www.docjar.com/html/api/org/codehaus/groovy/grails/orm/hibernate/validation/UniqueConstraint.java.html
The code looks like this:
if(shouldValidate) {
Criteria criteria = session.createCriteria( constraintOwningClass )
.add( Restrictions.eq( constraintPropertyName, propertyValue ) );
if( uniquenessGroup != null ) {
for( Iterator it = uniquenessGroup.iterator(); it.hasNext(); ) {
String propertyName = (String) it.next();
criteria.add(Restrictions.eq( propertyName,
GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(target, propertyName)));
}
}
return criteria.list();
}
So it depends on whether the GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue call will retrieve a property in the same class. Which based on the name it seems like it should.
I'm curious to know if it works for you.

Related

Combining Two List in Kotlin with Index

There is a data class as fruits.
data class Fruits(
val code: String, //Unique
val name: String
)
The base list indexed items with boolean variable is as below.
val indexList: MutableList<Boolean> = MutableList(baseFruitList.size) { false }
Now the Favourite Indexed list is as below
val favList: MutableList<Boolean> = MutableList(favFruitList.size) { true}
I want a combined full list which basically has the fav item indicated as true.
Ex:
baseFruitList = {[FT1,apple],[FT2,grapes],[FT3,banana],[FT4,mango],[FT5,pears]}
favList = {[FT2,grapes],[FT4,mango]}
The final index list should have
finalIndexed = {false,true,false,true,false}
How can we achieve in Kotlin, without iterating through each element.
You can do
val finalIndexed = baseFruitList.map { it in favList }
assuming, like #Tenfour04 is asking, that name is guaranteed to be a specific value (including matching case) for a specific code (since that combination is how a data class matches another, e.g. for checking if it's in another list)
If you can't guarantee that, this is safer:
val finalIndexed = baseFruitList.map { fruit ->
favList.any { fav.code == fruit.code }
}
but here you have to iterate over all the favs (at least until you find a match) looking to see if one has the code.
But really, if code is the unique identifier here, why not just store those in your favList?
favList = listOf("FT2", "FT4") // or a Set would be more efficient, and more correct!
val finalIndexed = baseFruitList.map { it.code in favList }
I don't know what you mean about "without iterating through each element" - if you mean without an explicit indexed for loop, then you can use these simple functions like I have here. But there's always some amount of iteration involved. Sets are always an option to help you minimise that

sort the table by column name Exposed Kotlin

Good afternoon, I want to make a universal sort for all tables. The idea is that the method will receive the name of the column as input and, through reflection, I will receive a link to the field of the same name.
val id = "id"
var a = JobSeekerTable::class
a.memberProperties.forEach { e ->
if (e.name == id) {
transaction {
JobSeeker.all().sortedBy { e.getter }
}
}
}
Unfortunately, this does not work. There was an option, through the fields field that the table has
JobSeekerTable.fields.forEach {v->
transaction {
JobSeeker.all().sortedBy { v }
}
}
but also unsuccessfully :(
If there is any way to refer to the required field through the name. Not using if and stuff like that?
First, you are probably looking for orderBy, not sortedBy. The former is to order SQL query results, the later is to sort a collection.
Second, you want to pass an instance of a column:
val id = "id"
JobSeekerTable.selectAll().orderBy(JobSeekerTable.columns.find {
it.name == id // Here I used the name you provided, although probably it should be named something like columnName
} !! to SortOrder.ASC)
Using "screaming" operator (!!) in Kotlin is a bad practice. So if all of your tables have ID column, for example, you can use "elvis" operator instead.
JobSeekerTable.selectAll().orderBy((JobSeekerTable.columns.find {
it.name == id
} ?: JobSeekerTable.id) to SortOrder.ASC)

lua:How to use value from table 'A', in table 'B', which nested in table 'A'

In real project, TEST_TABLE would contain much of TEST_TABLE_NESTED, each with its own testVariable and bunch of testScript. test function from testScript would be used in C++ code, and TEST_TABLE_NESTED tables would be added automatically from C++ code too.
TEST_TABLE =
{
TEST_TABLE_NESTED =
{
testVariable = 5,
testScript =
{
test = function()
print(testVariable, "hello") --How to access 'testVariable'?
end
}
}
}
EDIT :
This is the actual scenario of using this script:
GameObjectScriptTables =
{
GameObject_1 = --Container of scripts corresponding to some gameObject
{
gameObjectOwner = actual_object_passed_from_c++, --This is an actual object passed from c++
GameObjectScript_1 = --This is a script with update(dt) method which will be called somwhere in c++ code
{
update = function(dt)
--here I want to use some data from gameObjectOwner like position or velocity
end
}
}
GameObject_2 =
{
gameObjectOwner = actual_object_passed_from_c++,
GameObjectScript_1 =
{
update = function(dt)
--here I want to use some data from gameObjectOwner like position or velocity
end
},
GameObjectScript_2 =
{
update = function(dt)
--here I want to use some data from gameObjectOwner like position or velocity
end
}
}
--And so on
}
Idea is that exists some testVariable object (passed from C++), which data is used all over TEST_TABLE_NESTED. For me, above example looks natural for this task, but it prints nil instead of 5. So how to acces a testVariable from testScript without printing a full path like TEST_TABLE.TEST_TABLE_NESTED.testVariable?
You're asking for something like a "parent" pointer, which tells table B about table A, but that doesn't exist. Internally, the only association they have is that one of A's values happens to be B, but any number of tables could contain B as a value. Which is B's parent?
If you want B to know about A, you'll need to tell it. You can add an extra parameter to update which receives the game owner object, or update can be a closure which contains the game owner as a bound variable, so on and so forth.
I made it work by providing a gameObjectOwner instance for each GameObjectScript_N. However I don't know is it expensive solution or not.

Find all available values for a field in lucene .net

If I have a field x, that can contain a value of y, or z etc, is there a way I can query so that I can return only the values that have been indexed?
Example
x available settable values = test1, test2, test3, test4
Item 1 : Field x = test1
Item 2 : Field x = test2
Item 3 : Field x = test4
Item 4 : Field x = test1
Performing required query would return a list of:
test1, test2, test4
I've implemented this before as an extension method:
public static class ReaderExtentions
{
public static IEnumerable<string> UniqueTermsFromField(
this IndexReader reader, string field)
{
var termEnum = reader.Terms(new Term(field));
do
{
var currentTerm = termEnum.Term();
if (currentTerm.Field() != field)
yield break;
yield return currentTerm.Text();
} while (termEnum.Next());
}
}
You can use it very easily like this:
var allPossibleTermsForField = reader.UniqueTermsFromField("FieldName");
That will return you what you want.
EDIT: I was skipping the first term above, due to some absent-mindedness. I've updated the code accordingly to work properly.
TermEnum te = indexReader.Terms(new Term("fieldx"));
do
{
Term t = te.Term();
if (t==null || t.Field() != "fieldx") break;
Console.WriteLine(t.Text());
} while (te.Next());
You can use facets to return the first N values of a field if the field is indexed as a string or is indexed using KeywordTokenizer and no filters. This means that the field is not tokenized but just saved as it is.
Just set the following properties on a query:
facet=true
facet.field=fieldname
facet.limit=N //the number of values you want to retrieve
I think a WildcardQuery searching on field 'x' and value of '*' would do the trick.
I once used Lucene 2.9.2 and there I used the approach with the FieldCache as described in the book "Lucene in Action" by Manning:
String[] fieldValues = FieldCache.DEFAULT.getStrings(indexReader, fieldname);
The array fieldValues contains all values in the index for field fieldname (Example: ["NY", "NY", "NY", "SF"]), so it is up to you now how to process the array. Usually you create a HashMap<String,Integer> that sums up the occurrences of each possible value, in this case NY=3, SF=1.
Maybe this helps. It is quite slow and memory consuming for very large indexes (1.000.000 documents in index) but it works.

LinqToSQL Not Updating the Database

// goal: update Address record identified by "id", with new data in "colVal"
string cstr = ConnectionApi.GetSqlConnectionString("SwDb"); // get connection str
using (DataContext db = new DataContext(cstr)) {
Address addr = (from a in db.GetTable<Address>()
where a.Id == id
select a).Single<Address>();
addr.AddressLine1 = colValue.Trim();
db.SubmitChanges(); // this seems to have no effect!!!
}
In the debugger, addr has all the current values from the db table, and I can verify that AddressLine1 is changed just before I call db.SubmitChanges()... SQL Profiler shows only a "reset connection" when the SubmitChanges line executes. Anyone got a clue why this isn't working? THANKS!
You can get a quick view of the changes to be submitted using the GetChangeSet method.
Also make sure that your table has a primary key defined and that the mapping knows about this primary key. Otherwise you won't be able to perform updates.
Funny, to use GetTable and Single. I would have expected the code to look like this:
string cstr = ConnectionApi.GetSqlConnectionString("SwDb"); // get connection str
using (DataContext db = new DataContext(cstr))
{
Address addr = (from a in db.Address where a.Id == id select a).Single();
addr.AddressLine1 = colValue.Trim();
db.SubmitChanges(); // this seems to have no effect!!!
}
I got no idea what GetTable will do to you.
Another thing, for debugging Linq2SQL try adding
db.Log = Console.Out;
before SubmitChanges(), this will show you the executed SQL.
Thanks -- your comments will help me sort this out I'm sure! I didn't have the "Id" column defined as the PrimaryKey so that's an obvious non-starter. I would have expected that LinqToSQL would have thrown an error when the update fails. -- S.
Ok, here's the result. I can't use the form db.Address, because I didn't use the designer to create my database objects, instead I defined them as classes like this:
[Table(Name = "Addresses")]
public class Address
{
[Column(Name = "Id",IsPrimaryKey=true)]
public int Id { get; set; }
[Column(Name = "AddressLine1")]
public string AddressLine1 { get; set; }
...
Originally, I didn't have the "Id" column set as PK in the database, nor did I have it identified using IsPrimaryKey=true in the [Column...] specifier above. BOTH are required! Once I made that change, the ChangeSet found the update I wanted to do, and did it, but before that it told me that 0 rows needed to be updated and refused to commit the changes.
Thanks for your help! -- S.