My model.cto file -
namespace org.acme.mynetwork
participant Client identified by ClientId {
o String ClientId
o String ClientName
o String[] Policies
o String[] RFQAraay
}
participant Insurer identified by InsurerId {
o String InsurerId
o String InsurerName
o String[] RFQArray
o String[] Quotes
o String[] Policies
}
asset RFQ identified by RFQId {
o String RFQId
o String ClientId
o String InsurerName
o String TypeOfInsurance
o String RiskAmunt
o String Status
o String currentOwner
o String[] Quotes
o String[] SelectedInsurer
o String LeadInsurer
o String[] FinalInsurer
}
participant Broker identified by BrokerId {
o String BrokerId
o String BrokerName
o String[] Clients
}
asset Quote identified by QuoteId {
o String QuoteId
o String InsurerName
o String InsurerId
o String Premium
o String Capacity
o String RFQId
}
transaction GenerateRFQ {
o String RFQId
o String ClientId
o String InsurerName
o String TypeOfInsurance
o String RiskAmount
o String[] InsurerAddresses
}
My Script.js file
/**
* Insurance script file
* #param {org.acme.mynetwork.GenerateRFQ} generate - the trade to be processed
* #transaction
*/
function generateRFQ(generate){
var RFQId = generate.RFQId ;
var today = new Date();
var y = today.getFullYear();
var m = today.getMonth();
var d = today.getDate();
return getAssetRegistry('org.acme.mynetwork.RFQ').then(function(assetRegistry){
var RFQregistry = assetRegistry;
RFQregistry.RFQId = generate.RFQId;
RFQregistry.ClientId = generate.ClientId
RFQregistry.InsuredName = generate.InsurerName;
RFQregistry.TypeOfInsurance = generate.TypeOfInsurance;
RFQregistry.RiskAmount = generate.RiskAmount;
RFQregistry.Status = "RFQ fired on "+ d + m + y;
RFQregistry. Insurer = generate.InsurerAddresses;
return assetRegistry.update(RFQregistry);
})
}
I'm using online playground. Submitting this transaction gives me an error:
Could not find any functions to execute for transaction org.acme.mynetwork.GenerateRFQ#ae28a855-ba3c-48fe-9404-291ad95b24c7
I've tried changing its name but still no good. However SampleTransaction business logic is working fine.
your problem is that you have not modeled a transaction (in your .cto file) called GenerateRFQ as in: org.acme.mynetwork.GenerateRFQ in your decorator.
So add the following (below) to your model file - then do a composer network update to update your business network (and chaincode) to recognise the newly modeled transaction (that you call in your script).
transaction GenerateRFQ {
...add your model elements or relationships here
}
There is one issue I noticed in your script (which needs to be under the /lib subdirectory of your network project). You assign a new Date() - this is non-deterministic code, so each peer that would execute this will execute the 'date' function and get a different timestamp.
Also - other things that you may wish to consider - (based on the model you posted here):
Clients should be a relationship to Broker - see a sample network here -> https://github.com/hyperledger/composer-sample-networks/blob/master/packages/trade-network/models/trading.cto for an example of relationships. There may be in fact more relationships to consider in your model (eg one to many etc). Lastly your transaction should ideally have a relationship back to the participants and assets that are being 'referenced' in your code (eg. Client, Insurer etc). Again, look at the model file link I sent you to get an idea - also look at the other samples here -> https://github.com/hyperledger/composer-sample-networks/tree/master/packages for pointers and review the model language guide here -> https://hyperledger.github.io/composer/unstable/reference/cto_language.html
Related
I have a complexe application and I need to retrieve and filter 1000~5000 object for an xls export. Each object having multiple eager relationship (I need them for the export).
If I retrieve all the objects and their relationship as it is, I got some stackoverflow error.
Generaly when I need to make a big export, in order to make it efficient I use a DTO object with an #Query like this :
public interface myRepository extends JpaRepository<Car, Long> {
#Query("SELECT new com.blabla.myCustomObject(p.name, p.surname, c.model, c.number ...) "
+ "FROM Car c "
+ "LEFT JOIN c.person p "
+ "WHERE ... ")
List<myCustomObject> getExportCustomObject();
}
The problem is that the #Query is static and I want to add dynamic filter to my Query (Specifications, Criteria or some other system...)
How to do it ?
Specification cannot be used because this is only the where clause.
But you can use Criteria API. Here's an example. The BasicTeacherInfo is the DTO:
CriteriaQuery<BasicTeacherInfo> query = cb.createQuery(BasicTeacherInfo.class);
Root<Teacher> teacher = query.from(Teacher.class);
query.multiselect(teacher.get("firstName"),teacher.get("lastName"));
List<BasicTeacherInfo> results = em.createQuery(query).getResultList();
You can use #Param annotation to pass dynamic values to HQL, something like:
#Query("SELECT new com.blabla.myCustomObject(p.name, p.surname, c.model, c.number ...) "
+ "FROM Car c "
+ "LEFT JOIN c.person p "
+ "WHERE c.status = :status AND p.name = :name")
List<myCustomObject> getExportCustomObject(
#Param("status") Integer status,
#Param("name") String name
);
Below is one of the possible way where you can try to add offset and limit into your query you can make it dynamic with the help off placeholders.
Below is an sample pseudo code for reference:
Dao Layer:
#Query(value="SELECT e FROM tablename e WHERE condition_here ORDER BY e.id offset :offset limit:limit ")
public returnType yourMethod(String name, int offset, int limit);
Service Layer:
long count = number of records in db.
int a = // number of records to be fetched on each iterations
int num_iterations = count % a ;
int additionalrecords = count / a;
int start= 0;
while(num_iterations>0)
{
dao.yourMethod(start,a);
start = start+a;
count--;
// write your data to excel here
}
dao.yourMethod(start,additionalrecords);
Hope it is helpful.
I'm working with Hyperledger Composer and when i submit a transaction , i have to add manually the ID of Asset and Participiant. Is there a way to set up these ID automatically Without add it whenever i have to submit a transaction? Is there a javascript example code of smart contract ? Thanks.
CTO file
participant Patient identified by ID_P {
o String ID_P
o String name
o String surname
o String Birth regex=/[0-9]+\-[0-9]+\-[0-9]/
o String CF regex=/[A-Z0-9]{11}/
}
asset Health_Provision identified by ID_CF {
o String ID_CF
o Type type
o String[] Date regex=/[0-9]+\-[0-9]+\-[0-9]/
o String NoteFromToDoctor
o String NoteFromToCup
o String Receipt
o String SignNRE
o String Priority
o String Name
o String Surname
o String CF
o String Birth
o String Exemption
o RequestSubstitution substate
o Make_Health_Provision_Prescription[] requests optional
o Make_Health_Provision_Reservation[] reqs optional
--> Patient Applicant
--> Doctor doctor
--> CUP cup
}
transaction SendPrescription {
o String NoteFromToDoctor
o RequestSubstitution substate
--> Health_Provision IDCF
--> Patient Applicant
--> Doctor newDoctor
}
Logic.js
function SendPrescription(tx) {
var IDCF = tx.IDCF;
tx.IDCF.doctor = tx.newDoctor;
return getAssetRegistry('org.example.healthdata.Health_Provision')
.then(function (assetRegistry) {
return assetRegistry.update(tx.IDCF);
});
I explain better : when i submit the send prescription transaction , i have to add manually the ID Asset every time i want to submit a transaction. But i want to automate this transition and i don't understand how i could do that.
In this image , when i have to submit the transaction , there are random numbers associated to Asset ID , Patient ID and Doctor ID. I have to add mandatorily the ID of my Asset ,Patient and Doctor manually every time i submit the transaction? In your opinion can i automate that?
enter image description here
In my hyperledger composer app I want to write a named query that returns all persons with a certain hobby.
The model for "Person" is the following:
participant Person identified by id {
o String id
o String firstName
o String lastName
o String email
--> Hobby[] hobbies optional
}
The model for "Hobby" is the following:
asset Hobby identified by name {
o String name
}
The named query has the following structure:
query selectPersonsByHobby {
description: "Select all persons with a certain hobby."
statement:
SELECT org.comp.myapp.Person
WHERE //don't know what to put here//
}
I don't know what to put after the "WHERE" operator in order to achieve what I want.
I want something like the following:
query selectPersonsByHobby {
description: "Select all persons with a certain hobby."
statement:
SELECT org.comp.myapp.Person
WHERE (hobbies.contains(_$hobby))
}
Is this even possible ?
The short answer is that this query should work:
query selectConsultantsBySkill {
description: "Select all persons with a certain hobby."
statement:
SELECT org.comp.myapp.Person
WHERE (hobbies CONTAINS _$targetHobby)
}
But note that because your hobbies is an array of Relationships the targetHobby parameter will have to be something like resource:org.acme.Hobby#cycling . In a production scenario you would be 'calling' the query from a UI program so you could pre-pend the relationship syntax.
I guess this is just a test example, but I wonder if Hobby needs to be a relationship? It would be easier if not.
You could alternatively use a concept (and even an enumerated type within the concept!). Here is an example of a modified model and query with a concept:
participant Person identified by id {
o String id
o String firstName
o String lastName
o String email
o Interest[] passTime
}
concept Interest {
o String name
o String description
}
query selectConsultantsBySkill {
description: "Select all persons with a certain hobby."
statement:
SELECT org.comp.myapp.Person
WHERE (passTime CONTAINS (name == _$targetHobby ))
}
I have the following working query which selects based on the key and value of a joined map.
#Query("select e from Entity e join e.dataAttributes da where " +
"(key(da) =:attrKey1 and :attrVal1 in (value(da)) )")
List<Entity> findByAttrributeValues(#Param("attrKey1") String attrKey1,
#Param("attrVal1") String attrVal1);
I would like to select based on 2 keys and 2 values, but am having difficulties. The following likely very naiieve attempt returns no results:
#Query("select e from Entity e join e.dataAttributes da where " +
"(key(da) =:attrKey1 and :attrVal1 in (value(da)) ) and " +
"(key(da) =:attrKey2 and :attrVal2 in (value(da)) )")
List<Entity> findByTwoAttrributeValues(#Param("attrKey1") String attrKey1,
#Param("attrVal1") String attrVal1,
#Param("attrKey2") String attrKey2,
#Param("attrVal2") String attrVal2);
I'm new to JPA, any guidence would be appreciated
So I have this solution :
#Query("select e from Entity e join e.dataAttributes da join e.dataAttributes da2 where " +
"(key(da) =:attrKey1 and :attrVal1 in (value(da)) ) and " +
"(key(da2) =:attrKey2 and :attrVal2 in (value(da2)) )")
List<Entity> findByTwoAttrributeValues(#Param("attrKey1") String attrKey1,
#Param("attrVal1") String attrVal1,
#Param("attrKey2") String attrKey2,
#Param("attrVal2") String attrVal2);
I needed to join again onto the dataAttributes with a second identifier. Works as expected now. Might not be the prettiest. If there's a better way let me know
I'm very new to Linq, I can find multi-line data reading examples everywhere (by using foreach()), but what is the correct way of reading a single line of data? Like a classic Product Detail page.
Below is what I tried:
var q = from c in db.Products
where c.ProductId == ProductId
select new { c.ProductName, c.ProductDescription, c.ProductPrice, c.ProductDate };
string strProductName = q.First().ProductName.ToString();
string strProductDescription = q.First().ProductDescription.ToString();
string strProductPrice = q.First().ProductPrice.ToString();
string strProductDate = q.First().ProductDate.ToString();
The code looks good to me, but when I see the actual SQL expressions generated by using SQL Profiler, it makes me scared! The program executed four Sql expressions and they are exactly the same!
Because I'm reading four columns from a single line. I think I must did something wrong, so I was wondering what is the right way of doing this?
Thanks!
Using the First() extension method would throw the System.InvalidOperationException when no element in a sequence satisfies a specified condition.
If you use the FirstOrDefault() extension method, you can test against the returned object to see if it's null or not.
FirstOrDefault returns the first element of a sequence, or a default value if the sequence contains no elements; in this case the default value of a Product should be null. Attempting to access the properties on this null object will throw ArgumentNullException
var q = (from c in db.Products
where c.ProductId == ProductId
select new { c.ProductName, c.ProductDescription, c.ProductPrice, c.ProductDate }).FirstOrDefault();
if (q != null)
{
string strProductName = q.ProductName;
string strProductDescription = q.ProductDescription;
string strProductPrice = q.ProductPrice;
string strProductDate = q.ProductDate;
}
Also, you shouldn't have to cast each Property ToString() if you're object model is setup correctly. ProductName, ProductDescription, etc.. should already be a string.
The reason you're getting 4 separate sql queries, is because each time you call q.First().<PropertyHere> linq is generating a new Query.
var q = (from c in db.Products
where c.ProductId == ProductId
select new { c.ProductName, c.ProductDescription, c.ProductPrice, c.ProductDate }
).First ();
string strProductName = q.ProductName.ToString();
string strProductDescription = q.ProductDescription.ToString();
string strProductPrice = q.ProductPrice.ToString();
string strProductDate = q.ProductDate.ToString();