I have data on different costs per route per time of day for container transport (e.g., from zone A to zone B in the morning; the total costs of transport are 100 euros), for almost 200 zones with 4 times of day. How can I assign these costs in my Anylogic model per route per time of day?
(after this I would like agents (trucks) to decide (based on the costs) which route and time of day to travel)
Given no example data I am using some made-up data to give you an example of how to do this.
Suppose I have the following route and cost data
You can import this into the AnyLogic DB and then use them to populate a custom class with your data.
For example here is a custom Java class for your routes
public class MyRoute {
String id;
String from;
String to;
LinkedHashMap<String, Double> routeCosts = new LinkedHashMap<String, Double>();
/**
* Default constructor
*/
public MyRoute(String id, String from, String to) {
this.id = id;
this.from = from;
this.to = to;
}
public void addCost(String timeOfDay, double cost) {
routeCosts.put(timeOfDay, cost);
}
}
And then I have a little function to populate them from the DB
List<Tuple> rows = selectFrom(routes).list();
for (Tuple row : rows) {
MyRoute route = new MyRoute(
row.get( routes.route ),
row.get( routes.from_db ),
row.get( routes.to_db )
);
// Add costs
List<Tuple> costRows = selectFrom(costs)
.where(costs.route.eq(route.id))
.list();
for (Tuple costRow : costRows) {
route.addCost(
row.get( costs.time_of_day ),
row.get( costs.cost )
);
}
}
Now you can sort the routes based on the costs or time of day and use this to make your decisions
You can see more on sorting here https://www.baeldung.com/java-hashmap-sort
Related
I want to Create An Instance Of Room Data base in Composable
But
val db = Room.databaseBuilder(applicationContext, UserDatabase::class.java,"users.db").build()
is not working here not getting applicationContext
How to create an instance of context in composable
Have you tried getting the context with : val context = LocalContext.current and then adding this to get your applicationContext?
Like this: context.applicationContext or using simply val db = Room.databaseBuilder(context, UserDatabase::class.java,"users.db").build()
Room (and the underlying SQliteOpenHelper) only need the context to open the database (or more correctly to instantiate the underlying SQLiteOpenHelper).
Room/Android SQLiteOpenHelper uses the context to ascertain the Application's standard (recommended) location (data/data/<the_package_name>/databases). e.g. in the following demo (via Device Explorer):-
The database, as it is still open includes 3 files (the -wal and -shm are the Write Ahead Logging files that will at sometime be committed/written to the actual database (SQLite handles that)).
so roughly speaking Room only needs to have the context so that it can ascertain /data/data/a.a.so75008030kotlinroomgetinstancewithoutcontext/databases/testit.db (in the case of the demo).
So if you cannot use the applicationContext method then you can circumvent the need to provide the context, if using a singleton approach AND if after instantiating the singleton.
Perhaps consider this demo:-
First some pretty basic DB Stuff (table (#Entity annotated class), DAO functions and #Database annotated abstract class WITH singleton approach). BUT with some additional functions for accessing the instance without the context.
#Entity
data class TestIt(
#PrimaryKey
val testIt_id: Long?=null,
val testIt_name: String
)
#Dao
interface DAOs {
#Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(testIt: TestIt): Long
#Query("SELECT * FROM testit")
fun getAllTestItRows(): List<TestIt>
}
#Database(entities = [TestIt::class], exportSchema = false, version = 1)
abstract class TestItDatabase: RoomDatabase() {
abstract fun getDAOs(): DAOs
companion object {
private var instance: TestItDatabase?=null
/* Extra/not typical for without a context (if wanted)*/
fun isInstanceWithoutContextAvailable() : Boolean {
return instance != null
}
/******************************************************/
/* Extra/not typical for without a context */
/******************************************************/
fun getInstanceWithoutContext(): TestItDatabase? {
if (instance != null) {
return instance as TestItDatabase
}
return null
}
/* Typically the only function*/
fun getInstance(context: Context): TestItDatabase {
if (instance==null) {
instance = Room.databaseBuilder(context,TestItDatabase::class.java,"testit.db")
.allowMainThreadQueries() /* for convenience/brevity of demo */
.build()
}
return instance as TestItDatabase
}
}
}
And to demonstrate (within an activity for brevity) :-
class MainActivity : AppCompatActivity() {
lateinit var roomInstance: TestItDatabase
lateinit var dao: DAOs
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
roomInstance = TestItDatabase.getInstance(this) /* MUST be used before withoutContext functions but could be elsewhere shown here for brevity */
dao = roomInstance.getDAOs()
//dao.insert(TestIt(testIt_name = "New001")) /* Removed to test actually doing the database open with the without context */
logDataWithoutContext()
addRowWithoutContext()
addRowWithApplicationContext()
logDataWithoutContext()
}
private fun logDataWithoutContext() {
Log.d("${TAG}_LDWC","Room DB Instantiated = ${TestItDatabase.isInstanceWithoutContextAvailable()}")
for (t in TestItDatabase.getInstanceWithoutContext()!!.getDAOs().getAllTestItRows()) {
Log.d("${TAG}_LDWC_DATA","TestIt Name is ${t.testIt_name} ID is ${t.testIt_id}")
}
}
private fun addRowWithoutContext() {
Log.d("${TAG}_LDWC","Room DB Instantiated = ${TestItDatabase.isInstanceWithoutContextAvailable()}")
if (TestItDatabase.getInstanceWithoutContext()!!.getDAOs()
.insert(TestIt(System.currentTimeMillis(),"NEW AS PER ID (the time to millis) WITHOUT CONTEXT")) > 0) {
Log.d("${TAG}_ARWC_OK","Row successfully inserted.")
} else {
Log.d("${TAG}_ARWC_OUCH","Row was not successfully inserted (duplicate ID)")
}
}
private fun addRowWithApplicationContext() {
TestItDatabase.getInstance(applicationContext).getDAOs().insert(TestIt(System.currentTimeMillis() / 1000,"NEW AS PER ID (the time to seconds) WITH CONTEXT"))
}
}
The result output to the log showing that the database access, either way, worked:-
2023-01-05 12:45:39.020 D/DBINFO_LDWC: Room DB Instantiated = true
2023-01-05 12:45:39.074 D/DBINFO_LDWC: Room DB Instantiated = true
2023-01-05 12:45:39.077 D/DBINFO_ARWC_OK: Row successfully inserted.
2023-01-05 12:45:39.096 D/DBINFO_LDWC: Room DB Instantiated = true
2023-01-05 12:45:39.098 D/DBINFO_LDWC_DATA: TestIt Name is NEW AS PER ID (the time to seconds) WITH CONTEXT ID is 1672883139
2023-01-05 12:45:39.098 D/DBINFO_LDWC_DATA: TestIt Name is NEW AS PER ID (the time to millis) WITHOUT CONTEXT ID is 1672883139075
note that the shorter id was the last added but appears first due to it being selected first as it appears earlier in the index that the SQlite Query Optimiser would have used (aka the Primary Key).
basically the same date time second wise but the first insert included milliseconds whilst the insert via AddRowWithApplicationContext drops the milliseconds.
I need to implement function to store some value with limit on updates once per week.
I'm implemented in following way:
class Example
{
//Stored in db
public int _value;
//Stored in db
public DateTime _updatedAt;
//Stored in db
public DateTime _canUpdateAfter;
//Constant in code
public TimeSpan _updateTimeout = TimeSpan.FromMinutes(1);
public void StoreValue1(int value)
{
if (DateTime.Now - _updatedAt < _updateTimeout)
{
return;
}
_value = value;
_updatedAt = DateTime.Now;
}
public void StoreValue2(int value)
{
if (_canUpdateAfter > DateTime.Now)
{
return;
}
_value = value;
_canUpdateAfter = DateTime.Now + _updateTimeout;
}
}
I have two ways of implementing it:
Store updated time in db and calculate if timeout is passed in .net code.
Store value when timeout expire in db and compare it with current in .net code.
Which to use and why?
Both solutions are valid.
The only difference between the ways is the time to decide to set the possibility of the next update.
With solution 1 you make the decision every on code evaluation, with others you force the decision on the past.
I prefer solution 1; is more flexible, and sustainable.
Keep in mind the case of your business change update frequency. With solution 1 are enough new code deploy or change one row of your hypothetical configuration table, whereas whit solution 2 you will need to update all rows of the table.
I know we have result set to get a row as object But How can I get every field as a separate object ? consider of this database row :
user_id address_id product_id shop_id
5 3 134 2
I want to retrieve and save the row as follows :
userEntity AddressEntity ProductEntity ShopEntity
This is not how the TableDataGateway is supposed to be used, since what you are looking for are more complex features such as the ones of Doctrine 2 ORM and similar data-mappers.
Here is one possible solution to the problem, which involves using a custom hydrator (docs). My example is simplified, but I hope it clarifies how you are supposed to build your resultset.
First, define your entities (I'm simplifying the example assuming that UserEntity is the root of your hydration):
class UserEntity {
/* fields public for simplicity of the example */
public $address;
public $product;
public $shop;
}
class AddressEntity { /* add public fields here for simplicity */ }
class ProductEntity { /* add public fields here for simplicity */ }
class ShopEntity { /* add public fields here for simplicity */ }
Then, build hydrators specific for the single entities:
use Zend\Stdlib\Hydrator\HydratorInterface as Hydrator;
class AddressHydrator implements Hydrator {
// #TODO: implementation up to you
}
class ProductHydrator implements Hydrator {
// #TODO: implementation up to you
}
class ShopHydrator implements Hydrator {
// #TODO: implementation up to you
}
Then we aggregate these hydrators into one that is specifically built to hydrate a UserEntity:
class UserHydrator extends \Zend\Stdlib\Hydrator\ObjectProperty {
public function __construct(
Hydrator $addressHydrator,
Hydrator $productHydrator,
Hydrator $shopHydrator
) {
$this->addressHydrator = $addressHydrator;
$this->productHydrator = $productHydrator;
$this->shopHydrator = $shopHydrator;
}
public function hydrate(array $data, $object)
{
if (isset($data['address_id'])) {
$data['address'] = $this->addressHydrator->hydrate($data, new AddressEntity());
}
if (isset($data['product_id'])) {
$data['product'] = $this->productHydrator->hydrate($data, new ProductEntity());
}
if (isset($data['shop_id'])) {
$data['shop'] = $this->shopHydrator->hydrate($data, new ShopEntity());
}
return parent::hydrate($data, $object);
}
}
Now you can use it to work with your resultset. Let's define the service for your UserEntityTableGateway:
'UserEntityTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new UserHydrator());
return new TableGateway('user', $dbAdapter, null, $resultSetPrototype);
},
These are all simplified examples, but they should help you understanding how powerful hydrators can be, and how you can compose them to solve complex problems.
You may also check the chapters in the documentation about the Aggregate Hydrator and Hydration Strategies, which were designed specifically to solve your problem.
I have the following Entity :
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "DCOL", discriminatorType = DiscriminatorType.STRING)
#DiscriminatorValue("Alias")
public class Alias
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key key;
#Basic
private UUID from;
#Basic
private UUID to;
#Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
private Date createdOn;
public Alias() { /* intentionally blank */ }
public Alias(#Nonnull final UUID from, #Nonnull final UUID to)
{
this.key = KeyFactory.createKey(Alias.class.getSimpleName(), from.toString());
this.from = from;
this.to = to;
this.createdOn = new Date();
}
}
And here is the code that persists it :
final EntityManager em = EMF.TRANSACTIONS_OPTIONAL.createEntityManager();
try
{
final Alias a = new Alias(from, to);
em.persist(a);
}
finally
{
em.close();
}
Currently it takes 6 Write Operations to the Datastore to persist this Entity.
I reduced the number from 10 to 6 by marking createdOn with the #Extension to exclude it from the auto indexing. That is a 40% decrease in write ops!
Is there any way I can reduce the number of writes for something this simple?
Would using the low-level Datastore API directly make any improvement?
As you mentioned, your entity requires 6 write operations divided as follows:
1 write for the entity itself
1 write for the built-in EntitiesByKind index
2 writes for the from property (1 for the built-in index EntitiesByProperty and another for the built-in index EntitiesByPropertyDesc).
2 writes for the to property (1 for the built-in index EntitiesByProperty and another for the built-in index EntitiesByPropertyDesc).
The only opportunity you have at this point to reduce the number of writes is marking any of the from or to properties as unindexed as well (thus reducing the number of writes by 2 with each property).
You can see more information here: https://developers.google.com/appengine/docs/java/datastore/entities#Java_Understanding_write_costs
I am new to app-engine Datastore and to NoSQL world in common. I am developing a simple application where a user can declare his/her expenses everyday. Every user(Account) has its own declared expenses. The dash board contains a simple GWT Cell Tree which contains all the years in which the use declared expenses and when he/she clicks on a years, he gets all the months of the years then he clicks on the month and he gets all the days of the month and finally clicking on a day and he gets all the expenses declared in that day. It is something like
*2010
|_ jan
|_1
|_2
|_Food 12d
|_Dress 200d
|_Fun 150d
|_ ...
|_ feb
|_ ...
*2011
|_ jan
|_ feb
|_...
I save expenses entities in the data store for each user(Account) as the account the parent of all the expenses. my expense is as follow:
public class Expense implements Serializable, Comparable {
private String name;
private double price;
private Date date;
public Expense(String name, double price, Date date) {
this.name = name;
this.price = price;
this.date = date;
}
public Expense() {
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
public boolean isPriceValid() {
return price > 0;
}
public void setName(String name) {
this.name = name;
}
public void setPrice(double price) {
this.price = price;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
#Override
public int compareTo(Expense expense) {
if (name.equals(expense.getName())) {
if (date.equals(expense.getDate())) {
return new Double(price).compareTo(expense.getPrice());
}
return date.compareTo(expense.getDate());
}
return name.compareTo(expense.getName());
}
My QUESTION IS: How to query the expenses in the data store and return all different years relater to a specified Account and put them in a list or set or anything else where I can list them ? does I need to fetch all the expenses entities and iterate over them and get all the different years. doesn't sound reasonable. Any advice will be welcome and THANKS IN ADVANCE.
Several comments related to your post :
--> I wouldn't store a financial amount as a Double. Going that route will lead you to big problems with rounding errors. There are a lot of posts on this one. I would suggest you to store it as "DollarCent" and declare it as an integer. You simply multiply the amount by 100 when you store it and when displaying it you divide by 100.
--> Why do you declare your entity in the Datastore as implementing Serializable ? I would store without Serializable.
--> Related to the specific question on displaying the data by year, reading your question I see no other way than fetching the data. What I would do is ask GAE to order the data to avoid having to order it afterwards. Using Objectify, it would simply be q.filter(...).order(-date).order(amount).
Hope this helps !
Hugues