In Orientdb 3.0 RC1 (Tinkerpop/Gremlin community edition) I have 2 vertex classes:
- 'Company' with 1 property 'address'
- 'Address' with 1 property 'address' having a UNIQUE_HASH_INDEX on this property
Need to create edges of class 'Location' between 'Company' vertexes to the corresponding 'Address' vertex based on having the same 'address' property value.
First I tried using Gremlin the following way:
g.V().hasLabel("Company").as("a").
V().hasLabel("Address").as("b").
where("a", eq("b")).by("address").
addE("Location").next()
But the mid-traversal is not hitting the index .....I guess the OrientDB-Gremlin implementation not complete yet or my above query not good.
Then I converted the above to use a sideEffect():
g.V().hasLabel("Company").sideEffect{g.V().hasLabel("Address").has("address",it.get().property('address').value()).addE('Location').from(it.get()).next()}
but after quickly adding around 1k edges the query abruptly aborts and the OrientDB logs a lot of warnings like this:
"WARNI {db=ter1050} This database instance has 1280 open command/query result sets, please make sure you close them with OResultSet.close()"
So once again .....my query has a problem or I hit a bug.
I didn't find a way to do it in OrientDB SQL also.
I know this can be done using Tinkerpop API in Java but I was hoping for something more simple.
Try this:
OrientDB orientDB = new OrientDB("remote:localhost/", "<username>", "<password>", OrientDBConfig.defaultConfig());
ODatabaseDocument db = orientDB.open("<db name>","<username>", "<password>");
OResultSet result = db.command("select from Company");
OResultSet address_class = db.command("select from Address");
List<OResult> company = new ArrayList<OResult>();
List<OResult> address = new ArrayList<OResult>();
while(result.hasNext())
{
OResult record = result.next();
company.add(record);
}
while(address_class.hasNext())
{
OResult record = address_class.next();
address.add(record);
}
for(int i = 0; i < company.size(); i++)
{
String company_address = company.get(i).getProperty("address");
for(int j = 0; j < address.size(); j++)
{
String addresses = address.get(j).getProperty("address");
if(company_address.equals(addresses))
{
ORecordId company_rid = company.get(i).getProperty("#rid");
ORecordId addresses_rid = address.get(j).getProperty("#rid");
db.command("create edge Location from " + company_rid + " to " + addresses_rid);
}
}
}
db.close();
orientDB.close()
this is the result:
Hope it helps
Regards
Related
I need to know the correct way to handle SQL Injection when using the FromSQL command.
At runtime, I need to dynamically create a where statement. So I am using FromSql to create the SQL command. Now I know that using use string interpolation is the way to go. However, I need to step through a list of "Where Parameters" to generate the command. Simple enough to do;
foreach (var x in wp)
{
if (!string.IsNullOrEmpty(results))
results = $"{results} and {x.Field} = {x.Value}";
if (string.IsNullOrEmpty(results))
results = $"where {x.Field} = {x.Value}";
}
Problem is that this return a simple string and would not be string interpolation. How can I do this correctly?
Entityframework will parameterize your queries if you put it in the following format:
db.something.FromSql("SELECT * FROM yourTable WHERE AuthorId = {0}", id)
Is x.Field a form field that has a fixed number of possibilities? i.e. title, firstname etc. If so then something like the following:
var sqlstring = new StringBuilder();
var sqlp = new List<SqlParameter>();
var i = 0;
foreach (var x in wp)
{
var param = "#param" + i.ToString();
if (i!=0)
{
sqlstring.Append($" AND {x.Field} = " + param);
sqlp.Add(new SqlParameter(param, x.Value));
}
if (i==0)
{
sqlstring.Append($"WHERE {x.Field} = " + " #param" + i.ToString());
sqlp.Add(new SqlParameter(param, x.Value));
}
i++;
}
You'd then need to do something like this:
db.something.FromSql(sqlstring.ToString(), sqlp.ToArray())
Might be a better/cleaner way but that should work.
My solution to this problem is a VS extension, QueryFirst. QueryFirst generates a C# wrapper for sql that lives in a .sql file. As such, parameters are the only way to get data into your query and SQL injection is near impossible. There are numerous other advantages: you edit your sql in a real environment, it's constantly validated against your db, and using your query in your code is very simple.
Need to sort/order a list of data based on an undetermined number of columns (1 or more).
What i'm trying to do is loop through the desired columns and add an OrderBy or ThenBy based on their number to the query'd list, but i'm unsuccessful...
Done this, but it doesn't compile:
var query = GetAllItems(); //returns a IQueriable list of items
//for each selected column
for (int i = 0; i < param.Columns.Length; i++)
{
if (i == 0)
{
query = query.OrderBy(x => x.GetType().GetProperty(param.Columns[i].Name));
}
else
{
//ERROR: IQueriable does not contain a definition for "ThenBy" and no extension method "ThenBy"...
query = query.ThenBy(x => x.GetType().GetProperty(param.Columns[i].Data));
}
}
How can i resolve this issue? Or any alternative to accomplish this requirement?
SOLUTION: #Dave-Kidder's solution is well thought and resolves the compile errors i had. Just one problem, OrderBy only executes (actually sorts the results) after a ToList() cast. This is an issue because i can't convert a ToList back to an IOrderedQueryable.
So, after some research i came across a solution that resolve all my issues.
Microsoft assembly for the .Net 4.0 Dynamic language functionality: https://github.com/kahanu/System.Linq.Dynamic
using System.Linq.Dynamic; //need to install this package
Updated Code:
var query = GetAllItems(); //returns a IQueriable list of items
List<string> orderByColumnList = new List<string>(); //list of columns to sort
for (int i = 0; i < param.Columns.Length; i++)
{
string column = param.Columns[i].Name;
string direction = param.Columns[i].Dir;
//ex.: "columnA ASC"
string orderByColumn = column + " " + direction;
//add column to list
orderByColumnList.Add(orderBy);
}
//convert list to comma delimited string
string orderBy = String.Join(",", orderByColumnList.ToArray());
//sort by all columns, yay! :-D
query.OrderBy(orderBy).ToList();
The problem is that ThenBy is not defined on IQueryable, but on the IOrderedQueryable interface (which is what IQueryable.OrderBy returns). So you need to define a new variable for the IOrderedQueryable in order to do subsequent ThenBy calls. I changed the original code a bit to use System.Data.DataTable (to get a similar structure to your "param" object). The code also assumes that there is at least one column in the DataTable.
// using System.Data.DataTable to provide similar object structure as OP
DataTable param = new DataTable();
IQueryable<DataTable> query = new List<DataTable>().AsQueryable();
// OrderBy returns IOrderedQueryable<TSource>, which is the interface that defines
// "ThenBy" so we need to assign it to a different variable if we wish to make subsequent
// calls to ThenBy
var orderedQuery = query.OrderBy(x => x.GetType().GetProperty(param.Columns[0].ColumnName));
//for each other selected column
for (int i = 1; i < param.Columns.Count; i++)
{
orderedQuery = orderedQuery.ThenBy(x => x.GetType().GetProperty(param.Columns[i].ColumnName));
}
you should write ThenBy after OrderBy like this:
query = query
.OrderBy(t=> // your condition)
.ThenBy(t=> // next condition);
I am using Orientdb 2.2.12.
I want to set an auto-increment property to vertex
e.g
for(i 1 to 100)
{
vertex.setProperty("counter", AUTO_INCREMENT_Value(start = 0))
}
I tried to achieve this by creating sequence
sequenceLibrary.createSequence(AUTO_INCREMENT_Value, SEQUENCE_TYPE.ORDERED, new OSequence.CreateParams().setStart((long) 0));
for(int i=1 ; i<=100; i++)
{
vertex.setProperty("counter", AUTO_INCREMENT_Value);
graph.commit();
graph.shutdown();
}
Though it work fine in single threaded system but in multithreaded system it gave ambiguous results.
I gave each thread a seperate OrientGraph instance from OrientGraphfactory as stated in official doc :
OrientGraphFactory graphFactory = new OrientGraphFactory(
"remote:" + IP + ":" + PORT+ "/" + appName).setPool(1, 100);
OrientGraph graph = graphFactory.getTx();
Is there any way to achieve this in orientdb.
Thanks..!
I am using Npgsql for postgresql in C++/CLI. So, the problem is, I have a db on my computer, and I am trying to select some of data from it's "movies" table. I already entered some data inside it, so I know that it has some data. But when I try to select some of them, answer to my query is empty. My code is like below:
public: string* SelectData(string* torrent)
{
conn->Open();
String ^ query = "SELECT title, director, actors, genre FROM movies";
Npgsql::NpgsqlCommand ^ command = gcnew NpgsqlCommand(query, conn);
try{
Npgsql::NpgsqlDataReader ^ dr = command->ExecuteReader();
for (int i = 0; i < N_TORRENT; i++)
{
if(dr->Read())
{
string std1 = toStandardString((String^)dr[0]);
string std2 = toStandardString((String^)dr[1]);
string std3 = toStandardString((String^)dr[2]);
string std4 = toStandardString((String^)dr[3]);
torrent[i] = std1 + " " + std2 + " " + std3 + " " + std4;
}
}
return torrent;
}
finally{
conn->Close();
}
}
(For the ones who will look for this question's answer)
Problem solved when I changed my query and look for the "title" column that are not empty. But this is ridiculus, so I beleive the problem was about pgAdmin. Because my insert query was not working either, but I added "rowseffected" variable and it shows the effected row's number and looks like it is working. So the problem is probably about the pgAdmin.
I am trying to recreate a tax map within my system using Bing Maps. My problem is in listing the length, in feet, of the sides of the polygons I am creating. I have a good idea of how to get the length of polylines I am creating from the MSSQL 2012 geometry or geography items in my database. I cannot figure out how to present it to the user effectively though. I have two ideas for how I would like to do this.
Place the lengths directly on or adjacent to the polyline in question.
Create an emphasized point on the full polygon and list to the side of the map, the lengths of the sides of the polygon based on a clockwise order.
Either of the 2 options would work as an acceptable solution. I used this tutorial to create my current environment so I would be looking to integrate the solution into it in some way:
How to create a spatial web service that connects a database to Bing Maps using EF5
Note that my implementation only uses the countries part of the code so I do not need to deal with single points like cities that are in that tutorial.
The relevant piece of code that handles drawing on the map that I would need to edit can be found here:
Bing Maps v7 WellKnowTextModule
If you want to get the perimeter of a polygon in SQL2012 you can grab the exterior ring of it. The exterior ring will be a LineString i.e. "#g.STExteriorRing()". Then measure the length along that line. i.e. "#g.STExteriorRing().STLength()". However, countries are usually not just single Polygons, they can be MultiPpolygons, or GeometryCollections. So to calculate these lengths we have to do a bit more work. Here is a helper method you can add to the service to calculate the perimeters of these shapes:
private double CalculateLength(SqlGeometry geom)
{
double length = 0;
if(string.Compare(geom.STGeometryType().Value, "polygon", true) == 0)
{
}
else if (string.Compare(geom.STGeometryType().Value, "multipolygon", true) == 0)
{
int numPolygon = geom.STNumGeometries().Value;
for(int i = 1; i <= numPolygon; i++){
length += geom.STGeometryN(i).STExteriorRing().STLength().Value;
}
}
else if (string.Compare(geom.STGeometryType().Value, "geometrycollection", true) == 0)
{
int numGeom = geom.STNumGeometries().Value;
for (int i = 1; i <= numGeom; i++)
{
length += CalculateLength(geom.STGeometryN(i));
}
}
return length;
}
To get the length info from the server side to the client add a property to the Country or BaseEntity class like this:
[DataMember]
public double Perimeter { get; set; }
From here you can populate this value after the linq query is used to get the response results using a simple loop that calls the helper method from earlier:
for (int i = 0; i < r.Results.Count;i++)
{
var geom = SqlGeometry.STGeomFromText(new System.Data.SqlTypes.SqlChars(r.Results[i].WKT), 4326);
r.Results[i].Perimeter = CalculateLength(geom);
}
As for displaying the information on the map. An easy way to place the information on a polyline is to choose a coordinate along the line, perhaps the middle one, just get the # or coordinates in the line and find the middle index and use that coordinate for a pushpin. You can then create a custom push using either a background image with text, or using custom HTML:
http://www.bingmapsportal.com/ISDK/AjaxV7#Pushpins4
http://www.bingmapsportal.com/ISDK/AjaxV7#Pushpins15
Wanted to add an addendum to the answer I accepted as I feel it changes it a bit.
While working on this I found that I was not actually able to get each line segment's length via entity framework. This is due to the fact that the query required changing the geography I had back to a geometry then parse it to its base line segments and then change those line segments back to geographies. The query, even in SQL, would take minutes so it was not an option to run dynamically in EF.
I ended up creating another table in my database containing the parsed line segments for each side of each polygon I had. Then I could use the centroids of the line segments as faux cities. I then added this logic into the DisplayData javascript function from the tutorial mentioned in the question after the for loop in the method.
if (shape.getLength) {
} else {
var chkPolygon = data.Results[0].WKT.substring(0, data.Results[0].WKT.indexOf('(', 0));
chkPolygon = chkPolygon.replace(/\s/g, '');
switch (chkPolygon.toLowerCase()) {
case 'point':
case 'polygon':
var latlonCheck = map.getCenter();
var setSides = window.location.origin + "/SpatialService.svc/FindNearBy?latitude=" +
latlonCheck.latitude + "&longitude=" + latlonCheck.longitude +
"&radius=" + data.Results[0].ID + "&layerName=" + "city" + "&callback=?";
CallRESTService(setSides, DisplaySides);
default:
break;
}
}
the data.Results[0].ID would find all the line segments in the new table for that specific country. Then the DisplaySides function is used to overlay the html pushpins as "cities" over the appropriate points for each side on the map
function DisplaySides(getSides) {
infobox.setOptions({ visible: false });
if (getSides && getSides.Results != null) {
for (var i = 0; i < getSides.Results.length; i++) {
var sideLenFtShort = Math.round(getSides.Results[i].LengthFeet * 100) / 100;
var htmlLenString = "<div style='font-size:14px;border:thin solid black;background-color:white;font-weight:bold;color:black;'>" + sideLenFtShort.toString(); + "</div>";
var testString = {
pushpinOptions: { width: null, height: null, htmlContent: htmlLenString }
};
var sideCtr = WKTModule.Read(getSides.Results[i].WKT, testString);
dataLayer.push(sideCtr);
}
}
else if (getSides && getSides.Error != null) {
alert("Error: " + getSides.Error);
}
}