Find records with Many2Many using activeJDBC - many-to-many

I have these annotations for the models:
#Many2Many(other = Course.class, join = "registrations", sourceFKName = "student_uid", targetFKName = "course_uid")
public class Student extends Model {
}
#Many2Many(other = Student.class, join = "registrations", sourceFKName = "course_uid", targetFKName = "student_uid")
public class Course extends Model {
}
How do I get all Students belong to a course UID?

First, you do not need to specify the same annotation twice. This will work just the same:
public class Student extends Model {}
#Many2Many(other = Student.class, join = "registrations", sourceFKName = "course_uid", targetFKName = "student_uid")
public class Course extends Model { }
Second, your case is described on this page: http://javalite.io/many_to_many_associations#select-related-objects
so, you would:
Course course = Course.findById(id);
List<Student> students = course.getAll(Student.class);
That is all!

Related

Room returns incorrect initialized object from generated query

I have three tables, one containing Cards, one containing CardDecks and third one implementing a many-to-many relation between the former two and additionally containg a symbol for every relation entry.
My task is to get three columns from the card-table and the symbol from the relation-table and save it in a data Object specifically designed for handling those inputs, the codition being, that all entries match the given deckId. Or in (hopefully correct) sql-language:
#Query("SELECT R.symbol, C.title, C.type, C.source " +
"FROM card_table C JOIN cards_to_card_deck R ON C.id = R.card_id"+
"WHERE R.card_deck_id = :cardDeckId")
LiveData<List<CardWithSymbol>> getCardsWithSymbolInCardDeckById(long cardDeckId);
But the room implementation class generates:
#Override
public LiveData<List<CardWithSymbol>> getCardsWithSymbolInCardDeckById(long
cardDeckId) {
final String _sql = "SELECT R.symbol, C.title, C.typ, C.source FROM
cards_to_card_deck R INNER JOIN card_table C ON R.card_id = C.id WHERE
R.card_deck_id = ?";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1);
int _argIndex = 1;
_statement.bindLong(_argIndex, cardDeckId);
return new ComputableLiveData<List<CardWithSymbol>>() {
private Observer _observer;
#Override
protected List<CardWithSymbol> compute() {
if (_observer == null) {
_observer = new Observer("cards_to_card_deck","card_table") {
#Override
public void onInvalidated(#NonNull Set<String> tables) {
invalidate();
}
};
__db.getInvalidationTracker().addWeakObserver(_observer);
}
final Cursor _cursor = __db.query(_statement);
try {
final int _cursorIndexOfSymbol = _cursor.getColumnIndexOrThrow("symbol");
final List<CardWithSymbol> _result = new ArrayList<CardWithSymbol>(_cursor.getCount());
while(_cursor.moveToNext()) {
final CardWithSymbol _item;
final int _tmpSymbol;
_tmpSymbol = _cursor.getInt(_cursorIndexOfSymbol);
_item = new CardWithSymbol(_tmpSymbol,null,null,null);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
}
}
#Override
protected void finalize() {
_statement.release();
}
}.getLiveData();
}
Where
_item = new CardWithSymbol(_tmpSymbol,null,null,null);
should return my fully initialized object.
The CardWithSymbol class is declared as follows:
public class CardWithSymbol {
public int symbol;
public String cardName;
public String cardType;
public String cardSource;
public CardWithSymbol(int symbol, String cardName, String cardType, String cardSource){
this.symbol = symbol;
this.cardName = cardName;
this.cardType = cardType;
this.cardSource = cardSource;
}
And the types of the columns returned by the query are:
int symbol, String title, String type, String source
I already went through some debugging and the rest of the application works just fine. I can even read the symbol from the objects return by the query, but as mentioned above for some reason room ignores the other three parameters and just defaults them to null in the query-implementation.
So after some trial and error and reading through the dao-documentation once again i found my error:
When creating a class for handling subsets of columns in room, it is important to tell room which variable coresponds to which columns via #ColumnInfo(name = "name of the column goes here")-annotation.
So changing my CardWithSymbol class as follows solved the issue for me:
import android.arch.persistence.room.ColumnInfo;
public class CardWithSymbol {
#ColumnInfo(name = "symbol")
public int symbol;
#ColumnInfo(name = "title")
public String cardName;
#ColumnInfo(name = "type")
public String cardType;
#ColumnInfo(name = "source")
public String cardSource;
public CardWithSymbol(int symbol, String cardName, String cardType, String cardSource){
this.symbol = symbol;
this.cardName = cardName;
this.cardType = cardType;
this.cardSource = cardSource;
}
}

Using #JsonIgnore selectively on parent class fields

I have a Class A which is extended by multiple classes, say Class B, Class C and Class D.
However I want only Class D to ignore super class fields during serialization.
How do I implement this? If I use #JsonIgnore annotation on parent Class A, all child classes get impacted.
I can see 2 ways:
1 - You can use a JacksonAnnotationIntrospector to dynamically ignore fields, here we test if the field is from class A (see example below when serialising class C)
class CustomIntrospector extends JacksonAnnotationIntrospector {
#Override
public boolean hasIgnoreMarker(final AnnotatedMember m) {
return m.getDeclaringClass() == A.class;
}
}
2 - You can use the #JsonIgnoreProperties annotation to ignore the fields you don't want (see example below on the definition of class D)
Then with the following class
class A {
public String fieldA = "a";
}
class B extends A {
public String fieldB = "b";
}
class C extends A {
public String fieldC = "c";
}
#JsonIgnoreProperties(value = { "fieldA" })
class D extends A {
public String fieldD = "d";
}
Then use the ObjectMapper
public static void main(String[] args) throws Exception {
A a = new A();
String jsonA = new ObjectMapper().writeValueAsString(a);
System.out.println(jsonA);
// No filtering, will output all fields
B b = new B();
String jsonB = new ObjectMapper().writeValueAsString(b);
System.out.println(jsonB);
// Using the CustomIntrospector to filter out fields from class A
C c = new C();
ObjectMapper mapper = new ObjectMapper().setAnnotationIntrospector(new CustomIntrospector());
String jsonC = mapper.writeValueAsString(c);
System.out.println(jsonC);
// Using #JsonIgnoreProperties to filter out fields from class A
D d = new D();
String jsonD = new ObjectMapper().writeValueAsString(d);
System.out.println(jsonD);
}
outputs
{"fieldA":"a"}
{"fieldA":"a","fieldB":"b"}
{"fieldC":"c"}
{"fieldD":"d"}

Loading class attributes in Yii2

For example I have the following classes:
class A extends yii\base\Model {
public $attr1;
public $attr2;
}
class B extends yii\db\ActiveRecord {
... some attributes in table including attr1 and attr2 ...
}
Is it more elegant way to load() values from object B to object A than
$objectA = new A();
$objectB = new B();
... obtaining values for $objectB ...
$objectA->load([StringHelper::basename($objectB->className()) => $objectB->attributes])
?
You can do a
$objectA->attributes = $objectB->attributes;

Using a VO in actionscript between classes

In my class, I built a Weather VO (Visual Object) and now need to use it for another class.
How would I use it to modify the values of the text field in my second class? I attempted using getters and setters to no avail.
First Page:
vo=new WeatherVO();//Visual Object for the weather data
vo.city = _xmlData.channel.ns1::location.#city+", "+_xmlData.channel.ns1::location.#region;//city, st
vo.currentTemp = _xmlData.channel.item.ns1::condition.#temp;
vo.currentCondition = _xmlData.channel.item.ns1::condition.#text;
vo.currentCode = _xmlData.channel.item.ns1::condition.#code;
vo.sunrise = _xmlData.channel.ns1::astronomy.#sunrise;
vo.sunset = _xmlData.channel.ns1::astronomy.#sunset;
Second page:
public function set vo(value:WeatherVO):void
{
_weather=value;
}
public function get vo():WeatherVO
{
return _weather;
}
Your getters and setters should be methods of the WeatherVO class that aid in the modification and retrieval of properties within that class. With the limited code sample you have provided, my recommendation is to pass the weather data through your WeatherVO constructor like so.
public function WeatherVO(_city:String, _currentTemp:String, _currentCondition:String, _currentCode:String, _sunrisde:String, _sunset:String) {
city = _city;
currentTemp = _currentTemp;
currentCondition = _currentCondition;
currentCode = _currentCode;
sunrise = _sunrise;
sunset = _sunset;
}
//Here is an example getter and setter for the city value.
public function get City() {
return city;
}
public function set City(_city:String) {
city = _city;
}

A good(elegant) way to retrieve records with counts

Context: ASP.NET MVC 2.0, C#, SQL Server 2008, IIS7
I have 'scheduledMeetings' table in the database.
There is a one-to-many relationship: scheduledMeeting -> meetingRegistration
So that you could have 10 people registered for a meeting.
meetingRegistration has fields Name, and Gender (for example).
I have a "calendar view" on my site that shows all coming events, as well as gender count for each event.
At the moment I use Linq to Sql to pull the data:
var meetings = db.Meetings.Select(
m => new {
MeetingId = m.Id,
Girls = m.Registrations.Count(r => r.Gender == 0),
Boys = m.Registrations.Count(r=>r.Gender == 1)
});
(actual query is half-a-page long)
Because there is anonymous type use going on I cant extract it into a method (since I have several different flavors of calendar view, with different information on each, and I don't want to create new class for each).
Any suggestions on how to improve this?
Is database view is the answer?
Or should I go ahead and create named-type?
Any feedback/suggestions are welcome. My DataLayer is huge, I want to trim it, just don't know how.
Pointers to a good reading would be good too.
I'd extend your Meetings class by adding 2 properties:
public partial class Meeting
{
#region Properties
public int BoyCount { get; set; }
public int GirlCount { get; set; }
#endregion
}
With deferred loading:
var items = db.Meetings.Select(
m => new {
Meeting = m,
Girls = m.Registrations.Count(r => r.Gender == 0),
Boys = m.Registrations.Count(r = >r.Gender == 1)
}).ToList();
items.ForEach(i =>
{
i.Meeting.BoyCount = i.Boys;
i.Meeting.GirlCount = i.Girl;
});
List<Meeting> = items
.Select(i => i.Meeting)
.ToList();
With eager loading, one of the solutions is to load Registrations with your Meeting entity:
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Meeting>(m = > m.Registrations);
db.LoadOptions = loadOptions;
In this case the partial class properties above are became getters:
public partial class Meeting
{
#region Properties
public int BoyCount
{
get
{
return this.Registrations
.Count(r => r.Gender == 1);
}
}
public int GirlCount
{
get
{
return this.Registrations
.Count(r = > r.Gender == 0);
}
}
#endregion
}