Backendless Custom Event for Data aggregation - backendless

I am new to Backendless. I want to create a custom event to aggregate some data. I was only able to find one example for Custom Event.
The end goal is to get the most current review for each book of an author.
I have three tables: Authors, Books, and Reviews.
Is this the correct approach using java:
#BackendlessEvent( "Reviews" )
public class ReviewsEventHandler extends com.backendless.servercode.extension.CustomEventHandler
{
#Async
#Override
public Map handleEvent( RunnerContext context, Map eventArgs )
{
// find reviews based on author
StringBuilder whereClause = new StringBuilder();
whereClause.append( "Reviews.Books.Authors.Name = eventArgs" );
// sort newest update on top
QueryOptions queryOptions = new QueryOptions();
queryOptions.addSortByOption( "updateded DESC" );
BackendlessDataQuery dataQuery = new BackendlessDataQuery();
dataQuery.setQueryOptions( queryOptions );
dataQuery.setWhereClause( whereClause.toString() );
List<Reviews> reviews = Backendless.Persistence.of( Reviews.class ).find( dataQuery ).getCurrentPage();
return Reviews.emptyMap();
}
}

Your "whereClause" does not make sense. You end up having this and that will not do anything - will result in the "invalid whereclause" error:
Authors[Books] Authors.Name = {result of toString() from eventArgs}

Related

Dapper question. Getting values from returned object

Just started learning Dapper. I have an ADO.NET background. Using a demo I downloaded, I can insert/delete data from a webform into a MySql table just fine. This, however, I have searched all morning on.
In retrieving a single row from the db by ID, it doesn't return a LIST<>, it seems to be just an object (using code from the demo I downloaded). The query works, I get the object back. It has the fields: "ProductID, Description and Price".
The only way I could get the values to those three fields was like this:
System.Reflection.PropertyInfo pi = Product.GetType().GetProperty("ProductID");
System.Reflection.PropertyInfo desc = Product.GetType().GetProperty("Description");
System.Reflection.PropertyInfo price = Product.GetType().GetProperty("Price");
int _ProductID = (int)(pi.GetValue(Product, null));
string _Description = (string)(desc.GetValue(Product, null));
decimal _Price = (decimal)(price.GetValue(Product, null));
This works and gets the correct values for the three fields.
I'm used to looping through DataTables, but I just think there is probably a better way to get those values.
Is this the correct way to do this or am I missing something? I did actually read documentation and mess with this all morning before asking, too.
Some of the things I looked at seem to be very complex. I thought Dapper was supposed to simplify things.
OK, Thanks Marc. It was difficult for me to see what was supposed to be in the Dapper class files and what was supposed to be in my code behind. The original demo way of getting a product by ID had the query as .FirstOrDefault();
I changed everything to return a List<> and it all worked. I'm sure my ADO.NET is showing, but this works. In Dapper class files:
public List<Product> ProductAsList(int Id)
{
return this._db.Query<Product>("SELECT * FROM Cart_product WHERE ProductID=#Id", new { Id = Id }).**ToList()**;
}
This is just getting one row that matched the ProductID.
In page codebehind:
protected void CartItemAdd(string ProductId) // passing it the selected ProductID
{
var results = cartservice.ProductAsList(Convert.ToInt32(ProductId));
// returns that one row using Dapper ProductAsList(ProductId)
int _ProductId = 0;
string Description = string.Empty;
decimal Price = 0;
// Loop through the list and get the value of each item:
foreach (Product obj in results)
{
_ProductId = obj.ProductID;
Description = obj.Description;
Price = obj.Price;
}
// Using Dapper to insert the selected product into the shopping cart (table):
String UserName = "jbanks";
cartitem = new CartItem();
cartitem.ProductID = _ProductId;
cartitem.Quantity = 1;
cartitem.Description = Description;
cartitem.Price = Price;
cartitem.Created = DateTime.Now;
cartitem.CreatedBy = UserName;
result = cartservice.AddCartItem(cartitem);
if (result)
{
lblMessage.Text = string.Empty;
lblMessage.Text = "Successfully added a cart item";
}
}
}
It does indeed look up the product from one table and insert a selected item into another table.
Thanks again!
The main Query<T> API returns an IEnumerable<T>, which often will be a List<T>; the AsList<T>() extension method can get it back to a list without a copy, but either way: they are just T, for whatever T you asked for. If you asked for Query<Product>, then: they should be Product instances:
var results = connection.Query<Product>(someSql, someArgs); // perhaps .AsList()
foreach (Product obj in results) { // "var obj" would be fine here too
// now just use obj.ProductID, obj.Description and obj.Price
}
If that didn't work: check that you used the <T> version of Query. There is a non-generic variant too, which returns dynamic. Frankly, you should almost always use the <T> version.
Note: I'm assuming that somewhere you have something like
class Product {
public int ProductID {get;set;}
public string Description {get;set;}
public decimal Price {get;set;}
}

How to handle multiple session variables in ASP .Net?

As a part of online shopping, I implemented a cart using Session.
I have implemented the Cart in the following manner :
Session[pname] = qty;
where pname is a string variable which holds the name of the product and I used that as the key. qty is an integer variable which holds the number of items of that particular product.
To display the cart items I simply used the following loop :
foreach(string keys in Session.Keys)
Through this I get the names of the products along with the associated quantity and using this I display the cart items. The problem arises when I also have a session for the user active on the same page.
Session["uname"] = user_name;
And while retrieving the keys using Session.Keys, the uname gets included which I don't want as I need only the product's names. Is there any way I can read the keys from Session[pname] without reading from Session["uname"]?
Instead of storing an object in session for each product and quantity, just store a single object (e.g. List) which contains all of your cart items.
Here is an example which you could tweak to meet your needs:
First, a simple object to store the data:
public class CartItem {
public string Name { get; set; }
public int Quantity { get; set; }
}
Then if you need to add an object to the cart list:
var cartItems = new List<CartItem>();
cartItems.Add(new CartItem() {
Name = "",
Quantity = 1
});
Session["Cart"] = cartItems;
//Need to fetch the cart items later on?
cartItems = (List<CartItem>)Session["Cart"];
Obviously this can be implemented differently and this was just a quick example.
You mentioned needing an easier fix than what Justin Helgerson said, so here's a couple of suggestions, but they feel a little quick and dirty. Justin's is probably the superior solution. I used a quick Console app to demonstrate this, so place your constants where they belong, and you obviously don't have to create a dictionary.
const string USERSESSION = "uname";
Dictionary<string, object> session = new Dictionary<string, object>();
session["item1"] = 2;
session["item2"] = 1;
session[USERSESSION] = "StackOverflowUser";
// print cart items - minus the user name session key
foreach (string key in session.Keys.Where(s => s != USERSESSION))
{
Console.WriteLine("Key: {0} Value: {1}", key, session[key]);
}
Alternatively, if you plan on there being more keys than just "uname", use the Linq Except method.
// build up except set
List<string> exceptKeys = new List<string>
{
USERSESSION
};
foreach (string key in session.Keys.Except(exceptKeys))
{
Console.WriteLine("Key: {0} Value: {1}", key, session[key]);
}

Creating a list of keywords in the Content Delivery

Imagine I have a content type that has two fields of type category: one is a taxonomy Author and another one is a taxonomy Topics, these two taxonomies are unrelated, the only 'thing' they may have in common is the component itself.
Now we go to the website as a visitor, then when the visitor clicks on a given Author I want to create a list with all the Topics that are present in Components that also contain the specific Author.
I know I could create a query object with a criteria containing both keywords from the different taxonomies to check if it retrieves any values, the problem is that I would need to do that for every single topic i.e. Author and Topic1, Author and Topic2, Author and Topic 3 etc, in the end it may mean tens of queries which I obviously don't want to do.
As I see it the taxonomy API won't help because both taxonomies and thefore their keywords are completely unrelated. Any alternatives?
If I understand your requirement correctly, you could get this using the combination of CategoryCriteria and KeywordCriteria.
CategoryCriteria to specify which category the content tagged to in this case Topics.
KeywordCriteria to specify which category key value (e.g.; Author=Chris ).
PublicationCriteria pubCriteria = new PublicationCriteria(59); // publication scope
CategoryCriteria categoryCriteria = new CategoryCriteria("Topics");
KeywordCriteria taxonomyKeywordCriteria = new KeywordCriteria("Author", "Chris");
Criteria allCriteria = CriteriaFactory.And(
new Criteria[] { pubCriteria,
CriteriaFactory.And(new Criteria[] { categoryCriteria, taxonomyKeywordCriteria }) }
);
Query allComps = new Query(allCriteria);
string[] compIDs = allComps.ExecuteQuery();
Response.Write("<br /> Legth : " + compIDs.Length );
I believe you will need to make 2 KeywordCriteria
Criteria #1: Author = "Chris"
Criteria #2: Topic = "Topic1" or "Topic2" or "Topic3"
Then create a new AND criteria to combine the two
Hope that helps, please specify if you are using .NET or Java if you need some examples
Chris
So you want to find all components that are tagged with a specific author and then find the corresponding Topic keyword relations of the found components?
The TaxonomyRelationManager should be able to help you here:
TaxonomyRelationManager manager = new TaxonomyRelationManager();
string[] contentWithThisAuthor = manager.GetTaxonomyContent(new Keyword(taxonomyUriOfAuthors, authorUri), false);
Keyword[] relatedTopics = manager.GetTaxonomyKeywords(taxonomyUriOfTopics, contentWithThisAuthor, new Keyword[] {}, null, 16);
Based on the comment by Ram G and therefore taking as starting point the code example in live content, I have verified that the following solution works:
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Tridion.ContentDelivery.Taxonomies;
using Tridion.ContentDelivery.DynamicContent.Query;
using Tridion.ContentDelivery.DynamicContent;
namespace Asier.Web.UI
{
public class TagCloud : System.Web.UI.WebControls.WebControl
{
protected override void Render(HtmlTextWriter writer)
{
TaxonomyRelationManager relationManager = new TaxonomyRelationManager();
TaxonomyFactory taxFactory = new TaxonomyFactory();
string taxonomyUriWhichIWantTheKeywordsFrom = "tcm:69-265-512";
String[] componentUris = GetComponentUris();
String[] contextKeywordUris = GetKeywordUris();
Keyword[] contextKeywordArray = GetKeywordsFromKeywordUris(taxFactory, contextKeywordUris);
Keyword[] cloudFacets = relationManager.GetTaxonomyKeywords(taxonomyUriWhichIWantTheKeywordsFrom, componentUris, contextKeywordArray, new CompositeFilter(), 16);
ProcessKeywords(cloudFacets);
}
private static string[] GetComponentUris()
{
// This should probably be replaced with a Query object that
// retrieves the URIs dynamically
return new String[] { "tcm:69-3645-16", "tcm:69-3648-16", "tcm:69-3651-16" };
}
private static string[] GetKeywordUris()
{
// this should probably be passed in as a property of the control
return new string[] { "tcm:69-3078-1024" };
}
private static Keyword[] GetKeywordsFromKeywordUris(TaxonomyFactory taxFactory, String[] contextKeywordUris)
{
Keyword[] contextKeywordArray = new Keyword[contextKeywordUris.Length];
for (int i = 0; i < contextKeywordUris.Length; i++)
{
contextKeywordArray[i] = taxFactory.GetTaxonomyKeyword(contextKeywordUris[i]);
}
return contextKeywordArray;
}
private static void ProcessKeywords(Keyword[] cloudFacets)
{
for (int i = 0; i < cloudFacets.GetLength(0); i++)
{
if (cloudFacets[i].ReferencedContentCount > 0)
{
// Do whatever...
}
}
}
}
}
For creating the query object, take help of a component.
In the component, add these categories in seperate fields :
Topic (ListBox, with Multiple Selection)
Author (Dropdown, with single selection...or as desired).
In your case, select all the listbox options for Topic.
Suppose you have 3 keywords viz Topic 1,Topic 2,Topic 3.
So that keywords would be formed as:
KeywordCriteria topicCriteria1= new KeywordCriteria("Topic","Topic 1");
KeywordCriteria topicCriteria2= new KeywordCriteria("Topic","Topic 2");
KeywordCriteria topicCriteria3= new KeywordCriteria("Topic","Topic 3");
Criteria[] topicCriterias = {topicCriteria1,topicCriteria2,topicCriteria3};
Criteria OrCriteria = CriteriaFactory.Or(topicCriterias);
//Create Author Criteria
KeywordCriteria AuthorCriteria= new KeywordCriteria("Author","Author 1");
//And both results
mainCriteria =CriteriaFactory.And(AuthorCriteria, topicCriterias);
//Query
query.Criteria=mainCriteria;
For selecting all the Keywords related to topic, you can write a method instead of writting individually.
Hope this helps.

Select All Rows Using Entity Framework

I'm trying to select all the rows out of a database using entity framework for manipulation before they're sent to the form
var ptx = [modelname].[tablename]();
ptx.[tablename].Select(????)
what goes in the ????
I used the entitydatasource and it provide everything I needed for what I wanted to do.
_repository.[tablename].ToList();
Entity Framework has one beautiful thing for it, like :
var users = context.Users;
This will select all rows in Table User, then you can use your .ToList() etc.
For newbies to Entity Framework, it is like :
PortalEntities context = new PortalEntities();
var users = context.Users;
This will select all rows in Table User
How about:
using (ModelName context = new ModelName())
{
var ptx = (from r in context.TableName select r);
}
ModelName is the class auto-generated by the designer, which inherits from ObjectContext.
You can use this code to select all rows :
C# :
var allStudents = [modelname].[tablename].Select(x => x).ToList();
You can simply iterate through the DbSet context.tablename
foreach(var row in context.tablename)
Console.WriteLn(row.field);
or to evaluate immediately into your own list
var allRows = context.tablename.ToList();
If it's under a async method then use ToListAsync()
public async Task<List<DocumentTypes>> GetAllDocumentTypes()
{
var documentTypes = await _context.DocumentTypes.ToListAsync();
return documentTypes;
}
Old post I know, but using Select(x => x) can be useful to split the EF Core (or even just Linq) expression up into a query builder.
This is handy for adding dynamic conditions.
For example:
public async Task<User> GetUser(Guid userId, string userGroup, bool noTracking = false)
{
IQueryable<User> queryable = _context.Users.Select(x => x);
if(!string.IsNullOrEmpty(userGroup))
queryable = queryable.Where(x => x.UserGroup == userGroup);
if(noTracking)
queryable = queryable.AsNoTracking();
return await queryable.FirstOrDefaultAsync(x => x.userId == userId);
}
Here is a few ways to do it (Just assume I'm using Dependency Injection for the DbConext)
public class Example
{
private readonly DbContext Context;
public Example(DbContext context)
{
Context = context;
}
public DbSetSampleOne[] DbSamples { get; set; }
public void ExampleMethod DoSomething()
{
// Example 1: This will select everything from the entity you want to select
DbSamples = Context.DbSetSampleOne.ToArray();
// Example 2: If you want to apply some filtering use the following example
DbSamples = Context.DbSetSampleOne.ToArray().Where(p => p.Field.Equals("some filter"))
}
You can use:
ptx.[tablename].Select( o => true)

Entity Framework Updating with Related Entity

I'm using the EF to try to update an entity with ASP.NET. I'm creating an entity, setting it's properties then passing it back to the EF on a separate layer with the ID so the change can be applied. I'm doing this because I only store the ID of the entity when it's been bound to the UI controls.
Everything works for standard properties, but I can't update the Category.ID of a Product (a related entity). I've tried EntityKey, EntityReference and a few other but the category ID isn't saved. This is what I have:
Product product = new Product();
product.CategoryReference.EntityKey = new EntityKey("ShopEntities.Categories", "CategoryID", categoryId);
product.Name = txtName.Text.Trim();
... other properties
StockControlDAL.EditProduct(productId, product);
public static void EditProduct(int productId, Product product) {
using(var context = new ShopEntities()) {
var key = new EntityKey("ShopEntities.Products", "ProductID", productId);
context.Attach(new Product() { ProductID = productId, EntityKey = key });
context.AcceptAllChanges();
product.EntityKey = key;
product.ProductID = productId;
context.ApplyPropertyChanges("ShopEntities.Products", product);
context.SaveChanges();
}
}
I really want to use the EF but I seem to be having a few problems with using it with ASP.NET.
The reason this fails is two fold.
In order to update a Reference (i.e. Product.Category) you have to have the original reference value in the context too.
ApplyPropertyChanges(...) only applies to regular / scalar properties of the Entity, the reference is left unchanged
So I would do something like this (Note this code makes heavy use of a trick called stub entities to avoid mucking around with EntityKeys)
Product product = new Product();
// Use a stub because it is much easier.
product.Category = new Category {CategoryID = selectedCategoryID};
product.Name = txtName.Text.Trim();
... other properties
StockControlDAL.EditProduct(productId, originalCategoryID);
public static void EditProduct(Product product, int originalCategoryID ) {
using(var context = new ShopEntities())
{
// Attach a stub entity (and stub related entity)
var databaseProduct = new Product {
ProductID = product.ProductID,
Category = new Category {CategoryID = originalCategoryID}
};
context.AttachTo("Products", databaseProduct);
// Okay everything is now in the original state
// NOTE: No need to call AcceptAllChanges() etc, because
// Attach puts things into ObjectContext in the unchanged state
// Copy the scalar properties across from updated product
// into databaseProduct in the ObjectContext
context.ApplyPropertyChanges("ShopEntities.Products", product);
// Need to attach the updated Category and modify the
// databaseProduct.Category but only if the Category has changed.
// Again using a stub.
if (databaseProduct.Category.CategoryID != product.Category.CategoryID)
{
var newlySelectedCategory =
new Category {
CategoryID = product.Category.CategoryID
};
context.AttachTo("Categories", newlySelectedCategory)
databaseProduct.Category = newlySelectedCategory;
}
context.SaveChanges();
}
}
This will do the job, assuming no typos etc.
This is accepted answer to this question Strongly-Typed ASP.NET MVC with Entity Framework
context.AttachTo(product.GetType().Name, product);
ObjectStateManager stateMgr = context.ObjectStateManager;
ObjectStateEntry stateEntry = stateMgr.GetObjectStateEntry(model);
stateEntry.SetModified();
context.SaveChanges();
Have you tried out that?
[Updated, code on top does not work]
This is small extension property I used so next code block is easier to understand:
public partial class Product
{
public int? CategoryID
{
set
{
CategoryReference.EntityKey = new EntityKey("ShopEntities.Categories", "CategoryID", value);
}
get
{
if (CategoryReference.EntityKey == null)
return null;
if (CategoryReference.EntityKey.EntityKeyValues.Count() > 0)
return (int)CategoryReference.EntityKey.EntityKeyValues[0].Value;
else
return null;
}
}
}
and that worked for me (this time for sure):
System.Data.EntityKey key = new System.Data.EntityKey("ShopEntities.Products", "ProductID", productId);
object originalItem;
product.EntityKey = key;
if (context.TryGetObjectByKey(key, out originalItem))
{
if (originalItem is EntityObject &&
((EntityObject)originalItem).EntityState != System.Data.EntityState.Added)
{
Product origProduct = originalItem as Product;
origProduct.CategoryID == product.CategoryID;//set foreign key again to change the relationship status
context.ApplyPropertyChanges(
key.EntitySetName, product);
}
}context.SaveChanges();
For sure it's looks hacky. I think that the reason is because the EF relationships have status as entities (modified, added, deleted) and based on that status EF changes the value of foreign keys or deletes row if many to many relationship is in case. For some reason (don't know why) the relationship status is not changed the same as property status. That is why I had to set the CategoryReference.EntityKey on originalItem in order to change the status of the relationship.

Resources