Hi, I have the relationship table / model like the picture above.
A Teacher can take multiple trainings. A Training/Course can be a FormalTraining or not.
A Teacher may have many students.
Now I want to get list of Students whose teacher has taken a Course where IsFormalTraining == true.
How do I do that in .NET EF Core 2.2 ?
Edited:
models:
Teacher
{
int Id;
string Name;
ICollection<TeacherStudent> students ;
}
TeacherStudent{
int Id;
int TeacherId;
int StudentId;
}
Student {
int Id;
string Name;
}
TeacherTraining{
int Id;
int TeacherId;
int CourseId;
DateTime StartDate;
}
Course {
int Id;
string Name;
}
I'm making a few assumptions based on your classes so you might need to test and tweak, but I imagine it'll look something like this:
var students =
context.Students.Where(s =>
context.Teachers.Any(t =>
t.Students.Any(st => st.StudentId == s.Id) && context.TeacherTraining.Any(tt =>
tt.TeacherId == t.Id &&
context.Course.Any(c => tt.CourseId == c.Id && c.IsFormalTraining))));
I'm not able to debug this without rigging up a ton of stuff, so you might have to step through it. You could also break this up into more queries, it'll be easy to read and etc, but it probably won't be very efficient (granted, I don't know how efficient this is without running a test).
Related
This is my first time working with objectBox. I have unfortunately stumbled on this issue and I failed to solve it.
I have two entities Product and Order as below.
#Entity()
class Customer{
int id;
String name;
#Backlink()
final orders = ToMany<Order>();
Customer({
this.id = 0,
required this.name,
});
}
#Entity()
class Order{
int id;
String? orderNumber;
final customer = ToOne<Customer>();
Order({
this.id = 0,
this.orderNumber,
});
}
A customer can place many orders but an order can only be placed by one customer.
I believe a list of all the orders for a specific customer can be returned simply by;
customer.orders;
But I would like to return a stream of all the orders made by a specific customer to feed into a streamBuilder. something like Stream<List<Order>>.
I have tried to read through the objectBox docs and I see I have to do something with backlink but I have failed to make it work. I would be very greatful for any help here.
Try to create and watch a link query, e.g. something like
final builder = store.box<Order>().query()
builder.link(Order_.customer, Customer.id.equals(customerId));
Stream<Query<Order>> ordersByCustomer = builder.watch();
Source/Details: https://docs.objectbox.io/queries#add-query-conditions-for-related-entities-links
I'm using EF6 and I wondered if there's an option to use a property that is comprised of multiple other props like so:
class Student{
public int age;
public string name;
public int class;
public string ComplexProp {
get { return name + age; }
}
}
students.Where(x => x.class = 4 && x.ComplexProp == "myname5")
name, age, class are in the DB. ComplexProp is not. I saw other questions that were similar but a little different and I would like to know how to do it and if it isnt possible what are other alternatives I can use.
maybe its possible to "save" a query x => x.name + x.age and use later?
I'm new to Mongodb coming from relational databases and I'd also like to point out I'm using SpringBoot with JPA. If I were to build an automotive classified site where I would have thousands of Users and 100s of thousands of listings, how would I go about setting up the schema? I've read some articles that say normalizing nosql data is bad practices.
Anyhow lets say we have the following structure.
User
id
name
email
Cars
id
make
model
year
I would need to be able to list many cars with the User and what i've seen in my examples is it creates a nested array of cars within User. This would work great for user accounts where I'd like to provide the user with all their cars
Where I get a bit confused is with the cars. The cars need to be able to be searched very quickly and would not need the user info right away. In a sql db I would typically do a search against the cars (year, make, model) and grab the user later on if I needed it.
In mongodb, do you create a User document that contains a nested car array? or do you somehow create 2 documents that are both automatically maintained and search against the car document for performance reasons?
Sample code
#Document(collection = "person")
public class Person {
#Id
private String id;
private String firstName;
private String lastName;
// #DBRef(lazy = true)
private List<Listing> listings;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
#Document(collection = "listing")
public class Listing {
#Id
public String id;
public String year;
public String make;
public String model;
public String trim;
public Listing(String year, String make, String model, String trim) {
this.year = year;
this.make = make;
this.model = model;
this.trim = trim;
}
}
#Override
public void run(String... args) throws Exception {
repository.deleteAll();
List<Listing> listings = new ArrayList<>();
Listing listing = new Listing("2008", "Ford", "Focus", "SE");
//listingRepository.save(listing);
listings.add(listing);
Person person = new Person("Alice", "Smith");
person.setListings(listings);
// save a couple of customers
repository.save(person);
person = new Person("Bob", "Smith");
listings = new ArrayList<>();
listings.add(new Listing("2018", "Chrysler", "300", "S"));
person.setListings(listings);
repository.save(person);
// fetch all customers
System.out.println("Customers found with findAll():");
System.out.println("-------------------------------");
for (Person _person : repository.findAll()) {
System.out.println(_person);
}
System.out.println();
// fetch an individual customer
System.out.println("Person found with findByFirstName('Alice'):");
System.out.println("--------------------------------");
System.out.println(repository.findByFirstName("Alice"));
System.out.println("Persons found with findByLastName('Smith'):");
System.out.println("--------------------------------");
for (Person _person : repository.findByLastName("Smith")) {
System.out.println(_person);
}
List<Listing> _listings = listingRepository.findAll();
System.out.println("listings " + _listings.size());
_listings.forEach(v -> {
System.out.println(v.toString());
});
}
Going by your entity model,I think what you are looking for is analogous to Many to Many/One to Many relationship in a relational database. So you can go for One way Embedding or Two way Embedding in MongoDb.
For One way embedding, You can create a Car collection like below:
db.carCollection.insertMany([{
_id:1,
make: 'porcha',
model:'qwerty',
year:'2018'
},
{
_id:2,
make: 'ferrara',
model:'uiop',
year:'2018'
}])
You can then go on to create user collection as below:
db.userCollection.insert({
_id:1,
user:'Tom',
email:'tom#tom.com',
car_ids:[1,2]
})
The car_ids is an array which will hold the ids of cars that belong to the user.
You can fetch the cars belonging to an user as(using findOne to fetch the user. Search parameter should be an unique id. I am considering email to be unique here.Ideally it should be user's id) :
var user=db.userCollection.findOne({email:'tom#tom.com'})
db.carCollection.find({_id:{$in:user.car_ids}})
This will fetch you all the cars per user
For fetching cars only you can simply do:
db.carCollection.find({})
For Two way embedding you can have similar array (as in user collection) inside cars collection so that each car can be identified to its user.
I have created the object Person, I can deleted and modify it and I can also search for Person by his name or phonenumber... but I don't know for exemple how to search for a person by his ** home address**. Here is my code:
My entity Person.java:
public class Person{
private Long id;
private String name;
#ManyToOne(cascade = CascadeType.ALL)
private Address address;
....
}
My entity Address.java
public class Address{
...
private String streetName;
...
}
And here is the most interesting function that I am trying to modify to get what I want, I would like to search for Persons who live in xxx (streetName = xxx). Here is my function getByQuery:
public List<Person> getByQuery(PersonSearchQuery searchQuery) {
Map<String, String> criteriaQuery = new HashMap<String, String>();
if (searchQuery.getName() != null)
criteriaQuery.put("name",searchQuery.getName());
TypedQuery<Person> query = this.findByQuery(criteriaQuery);
return query.getResultList();
}
The object PersonSearchQuery contains just to attributes name (String) and streetName (String) and their getters.
Function findByQuery:
public TypedQuery<T> findByQuery(Map<String, String> criteriaQuery) {
CriteriaBuilder builder = this.em.getCriteriaBuilder();
CriteriaQuery<T> criteria = builder.createQuery(this.entityClass);
Root<T> root = criteria.from(this.entityClass);
criteria.select(root);
Predicate predicate = builder.conjunction();
if (criteriaQuery.size() != 0) {
for (String key : criteriaQuery.keySet()) {
try{
predicate = builder.and(predicate, builder.equal(root.<String>get(key), criteriaQuery.get(key)));
}catch(IllegalArgumentException e){
continue;
}
}
}
criteria.where(predicate);
return this.em.createQuery(criteria);
}
So I can search for Persons by their names by I cannot search for them by streetName the problem is my function getByQuery I would like to do something like this:
if (searchQuery.getStreetName() != null)
criteriaQuery.put("Address.streetName",searchQuery.getStreetName());
The problem is I don't know how to define the key in this case. Thanks for your help
I only use CriteriaBuilder if I have several similar Entities which needs to be used/rendered in the same way, so if person is the only Entity with an Address reference I would just use JPQL, like this:
entityManager.createQuery(
"select p from Person p where p.address.streetName like :streetName", Person.class)
.setParameter("streetName", "xyz" + "%").getResultList()
The main reason I tend to avoid CriteriaBuilder, is because it has a rather steep learning curve, and you need to write a lot of code to express very simple concepts. In contrast any developer familiar with SQL can read and maintain JPQL code.
These days I always use frameworks, like DeltaSpike Data (for EE) and Spring Data, they both implements most of the basic DAO/Repository features, so If you don't mind an extra dependency (and some magic) it can save you a lot of boilerplate JPA code.
I have a entity, name Product.It have two property is unit (byte) and unitName(String). unit property is mapped on database. Ex: 0:Kg ; 1:g;.... I want when input a valid unit, unit property is stored; unless, it save to unitName
Product
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "product_id")
private int productId;
#Column(name = "product_name")
private String productName;
#Column(name = "unit")
private Byte unit;
#Transient
private String unitName;
}
In unit text field, I use a UnitConvert
UnitConvert
public class UnitConverter implements IConverter<Byte> {
private static final long serialVersionUID = 4798262219257031818L;
public UnitConverter() {
}
#Override
public Byte convertToObject(String value, Locale locale) {
return Text.isEmpty(value) ? 0 : UtilCommon.getTaniCode(value);
}
#Override
public String convertToString(Byte value, Locale locale) {
return (value == null || value==0 ) ? "" : UtilCommon.getTaniName(value);
}
}
I only think about HiddenField to do that, but I don't know how to do that.
Someone know how to use or anything can help me. Thank you very much
So from what I understood you want to save the input of a Model to a different database property depending on certain checks before hand. You can do that in your Form.onSubmit() method.
A very simple implementation could look like this:
public ProductPanel(String id, final IModel<Object> productModel) {
super(id, productModel);
// we're putting the productModel into the constructor.
// Therefore it's guaranteed to be detached
// -> it's okay to have it with final modifier.
IModel<String> formModel = Model.of("");
Form<String> form = new Form<String>("form", formModel) {
#Override
protected void onSubmit() {
super.onSubmit();
String productName = getModelObject();
Object realProduct = productModel.getObject();
if (isAcceptableUnit(productName)) {
realProduct.setUnit(parseUnit(productName));
} else {
realProduct.setUnitName(productName);
}
layer.saveProduct();
}
};
add(form);
TextField<String> productName = new TextField<String>("textField", formModel);
form.add(productName);
}
private boolean isAcceptableUnit(String productName) {
// your logic to determine if it's okay to cast to byte here...
return true;
}
private byte parseUnit(String productName) {
// your logic to parse the String to byte here...
return 0;
}
Some additional comments since I'm uncertain if the code snippets you provided are just for simplicity or actually code pieces:
You should try to avoid declaring your db object Serializable. Should you use normal Model objects to save your DTOs wicket will actually serialize them and you won't be able to do anything with them (well with hibernate at least).
Database object should use LoadableDetachableModel and save the primary key to load the entity in the load() method of it.
This would enable you now to work directly on those objects by using CompoundPropertyModel etc (which has it's pros and cons which I will not explain in detail here).
Still in your case I would add an Model<String> to the form and let the server decide how the input should be handled and mapped to the actual domain object.