I have a table like
------------------
StudentId Name Subject Description
1 ABC CA Descr CA
2 ABC FM Descr FM
3 ABC MJ Descr MJ
4 ABC DM Descr DM
------------------
I have converted the data table to anonymous objects first
var studentPlain= from dr in tbl.AsEnumerable()
select new{
StudentId =Convert.ToInt32(dr["StudentId"]),
Name=Convert.ToString(dr["Name"]),
Subject =Convert.ToString(dr["Subject"]),
Description = Convert.ToString(dr["Description"])
}
class subj
{
public string Subject {get;set;}
public string Description {get;set;}
}
class student
{
public int StudentId {get;set;}
public string Name {get;set;}
public List<subj> subjects{get;set;}
}
I need to convert it to student object
Try this. This is not for DB but you will correct easily:
public class dbStudent
{
public int StudentId;
public string Name;
public string Subject;
public string Description;
}
public class subject
{
public string Subject;
public string Description;
}
public class student
{
public int StudentId;
public string Name;
public List<subject> subjects;
}
class Program
{
static void Main(string[] args)
{
var dbStudebts = new List<dbStudent>();
dbStudebts.Add(new dbStudent { StudentId = 1, Name = "Bob", Subject = "Math", Description = "High math" });
dbStudebts.Add(new dbStudent { StudentId = 1, Name = "Bob", Subject = "Geography", Description = "Mountains" });
dbStudebts.Add(new dbStudent { StudentId = 2, Name = "John", Subject = "Philosophy", Description = "Philosophy of life" });
var result = (from o in dbStudebts
group o by new { o.StudentId, o.Name } into grouped
select new student()
{
StudentId = grouped.Key.StudentId,
Name = grouped.Key.Name,
subjects = grouped.Select(c => new subject()
{
Subject = c.Subject,
Description = c.Description
}).ToList()
}).ToList();
}
}
Related
the SQLite database contains three tables 1) employee 2) skills 3) departments. The idea is this - the employee table stores data such as id, name, last_name, salary. Also, an employee has data such as skill and department, but there can be several data for one employee, so I created two separate skills and departments tables and linked them using the key to the employee table where the primary key for employee is id. Now with the help of id I need to display all the information about employee including his skills which can be several and departments. I implement the whole process using the ROOM library.
Here is the request I make
#Query("SELECT employ.id ,employ.name ,employ.last_name, employ.salary, " +
"skill.skill, department.department_name FROM employ INNER JOIN skill,department " +
"ON employ.id = :id AND skill.employ_id = :id AND department.employ_id = :id ")
AllAboutEmployee getAllAboutEmployee(String id);
Here is the AllAboutEmployee class whose object accepts the result of the request
public class AllAboutEmployee {
#ColumnInfo(name = "id")
private String id;
#ColumnInfo(name = "name")
private String name;
#ColumnInfo(name = "last_name")
private String lastName;
#ColumnInfo(name = "salary")
private String salary;
#ColumnInfo(name = "department_name")
private List<String> departmentsList; // THE ERROR IS ON THIS LINE
#ColumnInfo(name = "skill")
private List<String> skillList; // THE ERROR IS ON THIS LINE
public AllAboutEmployee(String id, String name, String lastName, String salary, List<String> departmentsList, List<String> skillList) {
this.id = id;
this.name = name;
this.lastName = lastName;
this.salary = salary;
this.departmentsList = departmentsList;
this.skillList = skillList;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getSalary() {
return salary;
}
public void setSalary(String salary) {
this.salary = salary;
}
public List<String> getDepartmentsList() {
return departmentsList;
}
public void setDepartmentsList(List<String> departmentsList) {
this.departmentsList = departmentsList;
}
public List<String> getSkillList() {
return skillList;
}
public void setSkillList(List<String> skillList) {
this.skillList = skillList;
}
}
So ther are two fields int the AllAboutEmployee class with the List type, in order to put several skills and several departments there. It is in these fields that an error occurs. Thank you in advance for your help
Wow.. that's so cool.. I was coding all day and got this error too!
You have to create a TypeCoverter to store your data into your Room's Database.
In this case you have two List, that are not types recognizable by Database, so you have to create an Converter for it to store as a String, and another method to do the inverse.
Something like:
class TypeCoverter{
#TypeConverter
fun arrayListToString(arrayList: ArrayList<String>?): String? {
if (arrayList.isNullOrEmpty()) return null
val string = StringBuilder()
for (item in arrayList) {
val isNotTheLastItemInTheArrayList = (item == arrayList.last()).not()
if (isNotTheLastItemInTheArrayList) {
string.append(item).append(COMMA)
} else {
string.append(item)
}
}
return string.toString()
}
}
#TypeConverter
fun stringToArrayList(string: String?): ArrayList<String>? {
when {
string.isNullOrEmpty() -> {
return null
}
string.contains(COMMA).not() -> {
val list = ArrayList<String>()
list.add(string)
return list
}
else -> {
return string.split(COMMA.toRegex()).dropLastWhile { it.isEmpty() } as ArrayList<String>
}
}
}
That's actually in Kotlin, but you can see how it works.
We work on Spring Boot and oracle LDAP (Oid) with Spring LDAP module. The connection to LDAP with spring is ok but when we want to create LDAP group with ldapTemplate.create() method we got this error from Jackson:
please help us that what's wrong here!thanks
Type definition error: [simple type, class javax.naming.Name]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of javax.naming.Name (no Creators, like default construct, exist)
//Group Entry
#Getter
#Setter
#Entry(objectClasses = {"top", "groupOfUniqueNames"}, base = "cn=Groups")
public final class Group {
private static final String BASE_DN = "dc=eis,dc=msc,dc=ir";
#Id
private Name dn;
#Attribute(name="cn")
#DnAttribute("cn")
private String name;
#Attribute(name = "displayName")
private String description;
#Attribute(name = "owner")
private String owner;
#Attribute(name="uniqueMember")
private Set members;
public Group() {
}
public Group(String name, Set members) {
Name dn = LdapNameBuilder.newInstance(BASE_DN)
.add("ou", "groups")
.add("cn", name)
.build();
this.dn = dn;
this.name = name;
this.members = members;
}
public Group(Name dn, String name, String description, String owner, Set members) {
this.dn = dn;
this.name = name;
this.description = description;
this.owner = owner;
this.members = members;
}
public void addMember(Name member) {
if (this.members == null){
this.members = new HashSet<>();
}
members.add(member);
}
public void removeMember(Name member) {
members.remove(member);
}
#Override
public String toString() {
return "Group{" +
"dn=" + dn +
", name='" + name + '\'' +
", members=" + members +
'}';
}
//Service
#Override
public int createOIDGroupByJob(Group group) {
try {
ldapTemplate.create(group);
return 1;
}catch (Exception e){
return 0;
}
}
#PostMapping("/api/ldap/group")
public ResponseEntity<?> add(#RequestBody Group group) {
int retVal = ldapService.createOIDGroupByJob(group);
if (retVal==1) {
return new ResponseEntity<>(HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.EXPECTATION_FAILED);
}
}
//in postman
{
"dn": {
"rdns": [
{
"value": "Groups",
"type": "cn"
},
{
"value": "some data",
"type": "cn"
}
]
},
"fullName": "some data",
"lastName": "some data"
}
Finally!! I solved the problem!the problem is the jackson want to Deserialized an interface!! (javax.naming.Name) and it is not woking!
I found the solution is that use #JsonCreator on constructor like this:
//User Ldap Entry
public User(Name dn, String name, String lastName, String group) {
this.dn = dn;
this.name = name;
this.lastName = lastName;
this.group = group;
}
#JsonCreator
public User(#JsonProperty("dn") #JsonDeserialize(as=LdapName.class) final Name dn) {
this.dn = dn;
}
By the above sample, in #JsonDeserialize(as=LdapName.class) I pass LdapName.class that is the one of Name implemention! it works fine:)
Could someone help me as I show the result of an inner join query in a view in Spring.
How do I return all fields from all inner join tables and show in view?
Ex from Model Class:
#NotEmpty(message="Destino não pode estar vazio")
private Integer idDestinoAgendamento;
private Integer idMotoristaAgendamento;
private Integer idAutomovelAgendamento;
private Integer idRotaAgendamento;
#NotEmpty(message="Data não pode estar vazia")
private String dataSolicitacaoPacApp;
#NotEmpty(message="Hora não pode estar vazia")
private String horaSolicitacaoPacApp;
#NotEmpty(message="Status não pode estar vazio")
private String statusAgendamento;
private Destino destino;
private Motorista motorista;
private Automovel automovel;
Ex do DAO:
public List buscarTodosAgendamentos()
{
String sql = "SELECT * FROM bAgendamento AS agendamento INNER JOIN bsDestino AS destino"
+ " ON agendamento.idDestinoAgendamento = destino.idDestino INNER JOIN"
+ " bsMotorista AS motorista ON agendamento.idMotoristaAgendamento = motorista.idMotorista "
+ " INNER JOIN bsAutomovel AS automovel ON agendamento.idAutomovelAgendamento = "
+ " automovel.idAutomovel INNER JOIN bsRota AS rota ON agendamento.idRotaAgendamento ="
+ " rota.idRota ORDER BY agendamento.dataSolicitacaoPacAPP ASC "
List list =
namedParameterJdbcTemplate.query(sql,getSqlParameterByModel(null), new AgendamentoMapper());
return list;
}
View (return fields object Destino, Automovel...):
c:forEach items="${listAgendamento}" var="agendamento"
${agendamento.idAgendamento}
${agendamento.cpfPacienteSolicitacaoPacApp}
${agendamento.idDestinoAgendamento}
${agendamento.idMotoristaAgendamento}
${agendamento.idAutomovelAgendamento}
${agendamento.idRotaAgendamento}
${agendamento.dataSolicitacaoPacApp}
${agendamento.horaSolicitacaoPacApp}
${agendamento.statusAgendamento}
public class SiteJoinCategory {
private Category category;
private Site site;
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public Site getSite() {
return site;
}
public void setSite(Site site) {
this.site = site;
}
}
public class Site {
private Integer siteId;
private String siteName;
private Integer categoryId;
public Integer getSiteId() {
return siteId;
}
public void setSiteId(Integer siteId) {
this.siteId = siteId;
}
public String getSiteName() {
return siteName;
}
public void setSiteName(String siteName) {
this.siteName = siteName;
}
public Integer getCategoryId() {
return categoryId;
}
public void setCategoryId(Integer categoryId) {
this.categoryId = categoryId;
}
}
public class Category {
private Integer categoryId;
private String categoryName;
public Integer getCategoryId() {
return categoryId;
}
public void setCategoryId(Integer categoryId) {
this.categoryId = categoryId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
}
#Component
public class SiteJoinCategoryDao {
#Resource
private JdbcTemplate jdbcTemplate;
public List findAll() {
String sql = "select site., cat. " +
"from t_site site inner join m_category cat " +
"ON site.category_id = cat.category_id";
RowMapper rowMapper = new SiteCategoryRowMapper();
List list = jdbcTemplate.query(sql, rowMapper);
return list;
}
/**
* RowMapper
*/
protected class SiteCategoryRowMapper implements RowMapper {
#Override
public SiteJoinCategory mapRow(ResultSet rs, int rowNum) throws SQLException {
SiteJoinCategory siteJoinCategory = new SiteJoinCategory();
Site site = new Site();
Category category = new Category();
site.setSiteId(rs.getInt("site.site_id"));
site.setSiteName(rs.getString("site.site_name"));
site.setCategoryId(rs.getInt("site.category_id"));
category.setCategoryId(rs.getInt("cat.category_id"));
category.setCategoryName(rs.getString("cat.category_name"));
siteJoinCategory.setSite(site);
siteJoinCategory.setCategory(category);
return siteJoinCategory;
}
}
}
View (exemplo:
${siteJoinCategory.site.siteName}
${siteJoinCategory.category.categoryName}
I am currently playing with Java 8 and I found a problem with Function. I would like ton know if there is a way to use function reference (name::methode) with a Function with tree parameters without declare a new functional interface (i.e. TriFunction).
I tried with currying way, but it doesn't work.
I have three classes :
Person.class
public class Person {
public enum Sex {
MALE, FEMALE
}
private String firstName;
private String lastName;
private Sex gender;
public Person(String firstName, String lastName, Sex gender) {
this.firstName = firstName;
this.lastName = lastName;
this.gender = gender;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public Sex getGender() {
return gender;
}
}
PersonFactory
public class PersonFactory {
public static Person create(String firstName, String lastName, String gender) {
// Check firstName Parameter
if(firstName == null || firstName.isEmpty()) {
throw new IllegalArgumentException("The firstName argument expect to not be null or empty");
}
// Check lastName Parameter
if(lastName == null || lastName.isEmpty()) {
throw new IllegalArgumentException("The lastName argument expect to not be null or empty");
}
// Check gender Parameter
if(gender == null || gender.isEmpty()) {
throw new IllegalArgumentException("The gender argument expect to not be null or empty");
} else {
switch(gender) {
case "M":
return new Person(firstName, lastName, Sex.MALE);
case "F":
return new Person(firstName, lastName, Sex.FEMALE);
default:
throw new IllegalArgumentException("The gender parameter is supposed to be either 'M' for male or 'F' for Female");
}
}
}
}
CsVPersonParser
public class CsvPersonParser {
public Person parseLine(String line, String separator, Function<String, Function<String, Function<String, Person>>> creator) {
String[] separedLine = line.split(separator);
String firstName = separedLine[0];
String lastName = separedLine[1];
String gender = separedLine[2];
return creator.apply(firstName).apply(lastName).apply(gender);
}
}
Here is my main class :
public class App {
public static void main(String[] args) {
final String IMAGINARY_CSV_FILE_LINE = "Jean,Dupont,M";
CsvPersonParser csvParser = new CsvPersonParser();
csvParser.parseLine("blabla", ",", PersonFactory::create);
}
}
The compilator show : The type PersonFactory does not define create(String) that is applicable here
It seems pretty logical. I have no solution. Is anyone can help me ?
I wonder why there is no way to do it simple without to create new things.
Probably a tri function is quite complex. I suggest that you use a builder to create a person.
The main reasons are, that you are not fixed on parameter ordering and you can extend your person. When you use a trifunction where all parameters are strings its often hard to say which parameter is the first/second/third. And when you want to add an address to a person it becomes more difficult to make it with generic classes like TriFunction.
My suggestion:
public interface PersonBuilder {
PersonBuilder withFirstName(String firstName);
PersonBuilder withLastName(String lastName);
PersonBuilder withGender(String gender);
Person create();
}
Concrete Implementation:
public class DefaultPersonBuilder implements PersonBuilder {
private String firstName;
private String lastName;
private String gender;
#Override
public PersonBuilder withFirstName(String firstName) {
this.firstName = firstName;
return this;
}
#Override
public PersonBuilder withLastName(String lastName) {
this.lastName = lastName;
return this;
}
#Override
public PersonBuilder withGender(String gender) {
this.gender = gender;
return this;
}
#Override
public Person create() {
// Check firstName Parameter
if (firstName == null || firstName.isEmpty()) {
throw new IllegalArgumentException("The firstName argument expect to not be null or empty");
}
[... your implementation using the fields]
}
}
Your parser method:
public Person parseLine(String line, String separator, PersonBuilder person) {
String[] separedLine = line.split(separator);
String firstName = separedLine[0];
String lastName = separedLine[1];
String gender = separedLine[2];
return person.withFirstName(firstName).withLastName(lastName).withGender(gender).create();
}
Now you can change the argument order oder add new fields to person without creating a function with 10 parameters. The parser interface is simpler now, too.
There is no way to do that what I wanted. However two other solutions is possible. Use a lambda instead of PersonFactory::create or create a new functional interface.
Here is the result :
New functional interface
#FunctionalInterface
public interface TriFunction<A, B, C, D> {
public D apply(A a, B b, C c);
}
Add a function parseLine with my new functional interface
public class CsvPersonParser {
// Currying style
public Person parseLine(String line, String separator, Function<String, Function<String, Function<String, Person>>> creator) {
String[] separedLine = line.split(separator);
String firstName = separedLine[0];
String lastName = separedLine[1];
String gender = separedLine[2];
return creator.apply(firstName).apply(lastName).apply(gender);
}
// New Functionnal interface style
public Person parseLine(String line, String separator, TriFunction<String, String, String, Person> creator) {
String[] separedLine = line.split(separator);
String firstName = separedLine[0];
String lastName = separedLine[1];
String gender = separedLine[2];
return creator.apply(firstName, lastName, gender);
}
}
My main class with solutions
public class App {
public static void main(String[] args) {
final String DATA_FILE_SEPARATOR = ",";
final String FAKE_CSV_LINE = "Jean,Dupont,M";
CsvPersonParser csvParser = new CsvPersonParser();
Person person;
// Use curryling style
person = csvParser.parseLine(FAKE_CSV_LINE, DATA_FILE_SEPARATOR, f -> l -> g -> PersonFactory.create(f, l, g));
System.out.println("Currying style : " + person.getFirstName() + " " + person.getLastName() + " " + person.getGender());
// Use new functionnal interface
person = csvParser.parseLine(FAKE_CSV_LINE, DATA_FILE_SEPARATOR, PersonFactory::create);
System.out.println("TriFunction style : " + person.getFirstName() + " " + person.getLastName() + " " + person.getGender());
// Use lambda style
person = csvParser.parseLine(FAKE_CSV_LINE, DATA_FILE_SEPARATOR, (a,b,c) -> PersonFactory.create(a, b, c));
System.out.println("Lambda style : " + person.getFirstName() + " " + person.getLastName() + " " + person.getGender());
}
}
If you have the following:
Public Class Person
{
public int Id;
Public String Name;
}
In Program.cs,
String[] employeeList = new String[]{ 3, 5, 7 }
How do you cast the employeeList into a List of Person. I was thinking it would look something like:
List<Person> persons = employeeList
.Select( e=> new {
Id = e.ToString(),
Name = e.ToString() + "hello"
} );
List<Person> persons = employeeList
// In the select part you just indicate the desired type to return
.Select(e => new Person {
Id = e.ToString(),
Name = e.ToString() + "hello"
}).ToList(); // and cast the resulted enumerable to List<Person>