Declaring tables in Slick - database

I've been getting errors when trying to do many-to-many relations in Slick. This test shows how to do many-to-many relations in Slick. I followed it but then go this error:
Select(TableNode, "id") found. This is typically caused by an attempt to use a "raw" table object directly in a query without introducing it through a generator
I then found out that this is caused by declaring your tables at a static location (an object) and then trying to import it (it works fine if the object is in the same block). http://slick.typesafe.com/doc/1.0.0/lifted-embedding.html#tables
Ok, so val T = new Table inside of an object is the answer. But now I'm getting this error:
recursive method bs needs result type
It doesn't need a result type if it is an object and not a val. I've heard of using a class but I can't find any examples on how to do this.
How do you declare many-to-many models and import them from somewhere else?
EDIT:
Here's a gist showing what I mean: https://gist.github.com/pjrt/5332311
If you run the first test, it will pass, no issue.
If you run the second test, the following error is thrown:
scala.slick.SlickException: Select(TableNode, "id") found. This is typically caused by an attempt to use a "raw" table object directly in a query without introducing it through a generator.
If you run the third test (using vals inside of objects instead of objects directly), you get this error:
recursive method bs needs result type
[error] val A = new Table[(Int, String)]("a") {
recursive value AToB needs type
[error] def as = AToB.filter(_.bId === id).flatMap(_.aFK)
I know why the errors are happening, but I want to know how people got around them. One way is to put the objects inside of a class and instantiating a class every time you want to use Slick (but this seems...weird). Another is to never use Slick-related stuff outside of the package (or at least many-to-many stuff) but that also seems bad.
My question, still is, how do you guys get around this? Is there a proper way?

The error message you showed makes me think that you defined your tables but tried to access them directly instead of using a for comprehension.
The test file you were referring has an example right at the bottom, after defining the many-to-many tables that goes like
val q1 = for {
a <- A if a.id >= 2
b <- a.bs
} yield (a.s, b.s)
q1.foreach(x => println(" "+x))
assertEquals(Set(("b","y"), ("b","z")), q1.list.toSet)
What you see is that object table A is used as a comprehension generator (i.e. a <- A)
Does your code access the tables in some other way?

Related

Rust - Can I make this diesel dsl::find() function more generic?

I have a function that uses diesel to get an object from a DB based off the given ID:
fn get_db_site(pool: web::Data<Pool>, site_id: u32) -> Result<Site, diesel::result::Error> {
let conn = pool.get().unwrap();
dsl::site.find(site_id).get_result::<Site>(&conn)
}
This function is going to be exactly the same for every table I want to run it on so I'm hoping to put it in it's own utils file so I don't have to type the same thing in every time. The only problem is in order to call that find I need to do
crate::schema::site::dsl::site.find and I'm not sure how I can make that call generic to take any type. I know there are type arguments but I don't think that would work here
I normally advise against making diesel things more generic as this leads to really complex trait bounds quite fast. You normally never want to do this in application code. (It's a different thing for libraries that need to be generic). I normally compare the situation with plain SQL. For example if someone complains that users::table.find(pk) feels like duplication, ask yourself the following question: Would you feel that SELECT … FROM users is duplicated in the corresponding query SELECT … FROM users WHERE id = $. (The diesel dsl statement is basically the same).
So to answer your actual question, the generic functions needs to look something like this:
(Not sure if I got all bounds right without testing)
fn get_db_thing<T, U, PK>(pool: web::Data<Pool>, primary_key: PK) -> Result<U, diesel::result::Error>
where T: Table + HasTable<Table = T>,
T: FindDsl<PK>,
U: Queryable<SqlTypeOf<Find<T, PK>>, Pg>
{
let conn = pool.get().unwrap();
T::table().find(primary_key).get_result::<U>(&conn)
}
As you can see the list of trait bounds is already much longer than just having the load inline in the corresponding functions. In addition all the details added while constructing the query would now be required as generic function argument. At least the type for T cannot be inferred by the compiler, so from a code size point of view this solution is not "simpler" than just not making it generic.

FireStore and maps/arrays, document-list to array in Kotlin

I've finally started to understand a lot of info regarding FireStore, but I'm wondering if I can get some assistance.
If I had a setup similar to or like this:
          races
                Android
                      name: Android
                      size: medium
                       stats          <---- this is the map
                                str: 10
                                sex: 12.... (more values)
How would I parse this? I am looking to make specific TextViews apply values found in the database so that I can simply update the database and my app will populate those values so that hard coding and code updating won't be nearly as troublesome in the future.
I currently use something like this:
val androidRef = db.collection("races").document("Android")
androidRef.get().addOnSuccessListener { document ->
if (document != null) {
oneOfTheTextViews.text = document.getString("str")
} else {
}
The issue is currently I can only seem to access from collection (races) / document (android) / then a single field (I have "str" set as a single field, not part of a map or array)
What would the best practice be to do this? Should I not nest them at all? And if I can reference said nesting/mapping/array, what functions need to be called? (To be clear, I am not asking only whether or not it is possible - the reference guides and documents allude to such - but what property/class/method/etc needs to be called in order to access only one of those values or point to one of those values?).
Second question: Is there a way to get a list of document names? If I have several races, and simply want to make a spinner or recycler view based on document names as part of a collection, can I read that to the app?
What would the best practice be to do this?
If you want to get the value of your str property which is nested within your stats map, please change the following line of code:
oneOfTheTextViews.text = document.getString("str")
to
oneOfTheTextViews.text = document.getString("stats.str")
If your str property is a number and not a String, then instead of the above line of code please use this one:
oneOfTheTextViews.text = document.getLong("stats.str")
Should I not nest them at all?
No, you can nest as many properties as you want within a Map.
Is there a way to get a list of document names?
Yes, simply iterate the collection and get the document ids using getId() function.

What is the difference between a model object queried by filter and an object queried by get() in Django?

I keep coming across this issue where I am trying to update a record using the update() method.
It always works when I query an object using filter.
my_dictionary = {"key":"Val","another":"Val"}
thing = Thing.objects.filter(pk=1)
thing[0].update(**my_dictionary) wrote it wrong in the original question.
thing.update(**my_dictionary)
When I query the object using get() it keeps telling me that the object has no method update()
my_dictionary = {"key":"Val","another":"Val"}
thing = Thing.objects.get(pk=1)
thing.update(**my_dictionary)
Isn't a model object the same in both cases? Why would one have an update method and the other one not? Any insight would be greatly appreciated.
The documentation is very explicit about this:
filter() will always give you a QuerySet, even if only a single object matches the query - in this case, it will be a QuerySet containing a single element.
If you know there is only one object that matches your query, you can use the get() method on a Manager which returns the object directly.
Your first snippet returns a QuerySet, which has an update method. The second snippet returns a model instance, which doesn't.
Note that you have not shown the exact code you are using: thing[0].update would give exactly the same error as the second snippet.
You're using QuerySet.update() and ModelInstance.save().
If you’re just updating a record and don’t need to do anything with the model object, the most efficient approach is to call update(), rather than loading the model object into memory. For example, instead of doing this:
e = Entry.objects.get(id=10)
e.comments_on = False
e.save()
...do this:
Entry.objects.filter(id=10).update(comments_on=False)

Accessing variable from other class returns null

I did a separate levelData class to be able to flexibly add levels. I was happy with it until my supervisor ordered me to convert my levelData into XML. I did an XML version of the levelData's data (question, answers, correct answer...). I used the old class and converted it so that it fetches the XML.
All seems well, I did traces of my answers array and it printed nicely...
But the headache started when I tried this.
// This code appears in a different class with
// currentLvl:LevelData initialized in the constructor.
quizHolder.ansA.ansHud.text = currentLvl.choices[1];
quizHolder.ansB.ansHud.text = currentLvl.choices[2];
quizHolder.ansC.ansHud.text = currentLvl.choices[3];
quizHolder.ansD.ansHud.text = currentLvl.choices[4];
// BTW, I can't make a for loop to do the same function as above. So wierd.
I tried to run it. it returned:
TypeError: Error #2007: Parameter text must be non-null.
at flash.text::TextField/set text()
at QuestionPane/setQuiz()
at QuestionPane/setQuestion()
at QuestionPane()
at LearningModule()
Where did I go wrong? I tried making a custom get function for it, only to get the same error. Thanks in advance. If I need to post more of the code, I will gladly do so =)
LevelData Class in PasteBin: http://pastebin.com/aTKC1sBC
Without seeing more of the code it's hard to diagnose, but did you correctly initialize the choices Array before using it? Failing that I think you'll need to post more code.
Another possible issue is the delay in loading the XML data. Make sure your data is set before QuestionPane tries to access it.
When did you call
quizHolder.ansA.ansHud.text = currentLvl.choices[1];
quizHolder.ansB.ansHud.text = currentLvl.choices[2];
quizHolder.ansC.ansHud.text = currentLvl.choices[3];
quizHolder.ansD.ansHud.text = currentLvl.choices[4];
these? You load the XML and on complete you fill the array, what is correct. but is the XML loaded and parsed to the time when you access (fill the TextFields) the choices array already?

C#, Linq data from EF troubles

I don't have much experience with programming. I am working (to learn) on a project. I am using C# 4.0 and WPF 4 with EF (SQLite). I am having problemw with LINQ.
Here is the code in question (I hope this is enough, let me know if more is needed)
private void cboSelectCompany_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
using (ShippingEntities context = new ShippingEntities())
{
var companies = from company in context.Deliveries
where company.State == cboSelectCompany.SelectedItem.ToString()
select company;
txtDeliveryName.Text = companies.Name;
txtDeliveryState.Text = companies.State;
}
The last two lines don't work. Am I misunderstanding what LINQ is returning? I just get this error
Error 5 'System.Linq.IQueryable<SqliteDemo.Delivery>' does not contain a definition for 'State' and no extension method 'State' accepting a first argument of type 'System.Linq.IQueryable<SqliteDemo.Delivery>' could be found (are you missing a using directive or an assembly reference?) c:\users\dan\documents\visual studio 2010\Projects\SqliteDemo\SqliteDemo\DeliveryCompanies.xaml.cs 49 51 SqliteDemo
If anyone could give me some pointers or to a good reference I would appreciate it
You're close!
Linq is returning a Queryable set of Deliveries, which hasn't executed yet. My guess based on reading your code is that you're expecting at most one result, and then you want to put those values into a UI of some sort. In that case what you'll want to do is:
Take your IQueryable and execute it
Make sure you grab the first (or, alternatively enforce that there is only one) row
Set the appropriate values in the UI.
So, leave the line with the query there, and then change the rest to something like this:
var company = companies.FirstOrDefault();
txtDeliveryName.Text = company.Name;
txtDeliveryState.Text = company.State;
Insert null-checking as appropriate, and go check out the differences between First, FirstOrDefault, Single, and SingleOrDefault to see which one seems most correct for your particular situation.
Well, looks like companies.State doesn't compile, because companies is a list of SqliteDemo.Delivery (and not just a SqliteDemo.Delivery).
What do you want to achieve? Imagine that your LINQ query returns several results, is it possible?
Just use companies.FirstOrDefault() or companies.Single() to access first item becouse by default LINQ returns collection of items not just single item.

Resources