Cassnadra large collection insert with nested object in C# - c#

I'm writing this question after long fight with Cassandra database. I would like to insert large collection (~1000000) of Movie objects:
public class Movie
{
public Guid Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public int Year { get; set; }
public string Genres { get; set; }
public int Rating { get; set; }
public string OriginalLanguage { get; set; }
public string ProductionCountry { get; set; }
public int VotingsNumber { get; set; }
public Director Director { get; set; }
}
with nested field Director:
public class Director
{
public Guid Id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public int Age { get; set; }
}
I'm using DataStax C# Driver and I tied different ways, but still nothing. Currently my code looks like this:
private void CreateSchema()
{
Session.Execute("CREATE KEYSPACE IF NOT EXISTS test WITH replication " +
"= {'class':'SimpleStrategy', 'replication_factor':3};");
Session.Execute("CREATE TYPE IF NOT EXISTS test.director (" +
"firstname text," +
"lastname text," +
"age int," +
");");
Session.Execute("CREATE TABLE IF NOT EXISTS test.Movies (" +
"id uuid," +
"title text," +
"description text," +
"year int," +
"genres text," +
"rating int," +
"originallanguage text," +
"productioncountry text," +
"votingsnumber int," +
"director frozen<director>," +
"PRIMARY KEY (id)" +
");");
}
public string TimeOfCollectionInsert(int collectionEntriesNumber)
{
var watch = new Stopwatch();
try
{
IList<Movie> moviesList = Movie.CreateMoviesCollectionForCassandra(collectionEntriesNumber);
var preparedStatements = new List<PreparedStatement>();
var statementBinding = new List<BoundStatement>();
for (int i = 0; i < collectionEntriesNumber; i++)
{
preparedStatements.Add(Session.Prepare("INSERT INTO test.Movies (id, title, description, year, genres, rating, originallanguage, productioncountry, votingsnumber, actors) VALUES (?,?,?,?,?,?,?,?,?,{ 'director': { firstname: 'DirectorName', lastname: 'DirectorLastname', age: 50 }});"));
}
for (int i = 0; i < collectionEntriesNumber; i++)
{
statementBinding.Add(preparedStatements[i].Bind(moviesList[i].Id, moviesList[i].Title, moviesList[i].Description, moviesList[i].Year, moviesList[i].Genres, moviesList[i].Rating, moviesList[i].OriginalLanguage, moviesList[i].ProductionCountry, moviesList[i].VotingsNumber));
}
watch.Start();
for (int i = 0; i < collectionEntriesNumber; i++)
{
Session.Execute(statementBinding[i]);
}
watch.Stop();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return watch.ElapsedMilliseconds.ToString();
}
Both methods runs successfuly, but I would like to create directors dynamically.
I will be grateful for any help.
btw. Is this good way for measure cassandra bulk insert performace?
Thanks,
P

You have to map your Cassandra UDT (user defined type) director to your Director C# class.
For more information, you should read the documentation :
http://docs.datastax.com/en/developer/csharp-driver/2.7/csharp-driver/reference/21features/mappingUdts.html

Related

Dapper Multi Mapping stops at 3rd lavel nesting

I have taken a question and modified it to form my question. I have a query that is mapping correctly from the initial class, to the second class and elements attached to the second class (3rd) but not elements attached to the 3rd class. an example as follows.
public class Part {
public int Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address {
public int Id { get; set; }
public string Street { get; set; }
public SiteOu Ou { get; set; }
}
public class SiteOu {
public int Id { get; set; }
public SiteOuName SiteOuN { get; set; }
}
public class SiteOuName
{
public int Id { get; set; }
public string Name { get; set; }
}
Dapper:
public void TestSplitOn()
{
var conn = new SqlConnection(#"Data Source=.\SQLEXPRESS;Integrated Security=true;Initial Catalog=db");
conn.Open();
const string sql = "select Id = 1, Name = 'My Part', " +
"Id = 2, Street = 'My Street', " +
"Id = 1, SiteOuNameId = '1'" +
"Id = 1, Name = 'My Site', " +;
var result = conn.Query<Part, Address, SiteOu, SiteOuName, Part>(sql, (part, address, siteOu, siteOuName) =>
{
part.Address = address;
address.Ou = siteOu;
SiteOu.SiteOuName = siteOuName
return part;
},
commandType: CommandType.Text
).FirstOrDefault();
}
If I remove SiteOuName from the Dapper mapping, the code works but doesn't map the SiteOuName object, but when I leave it as it is, it shows me that the address object reference is null.
As far as I can see there are couple of issues in your Dapper code.
Firstly, your query should be like;
const string sql = "select Id = 1, Name = 'My Part', " +
"Id = 2, Street = 'My Street', " +
"Id = 1, SiteOuNameId = '1'," +
"Id = 1, Name = 'My Site'";
You are missing a comma next to the SiteOuNameId = '1' and you have extra comma and '+' sign next to Name = 'My Site'
Secondly, your mapping is wrong, it should be like
part.Address = address;
address.Ou = siteOu;
siteOu.SiteOuN = siteOuName;
return part;
In your code, S is upper case which makes complier think you are using the SiteOu class.
Also, SiteOu class doesn't have a property named SiteOuName, it should be SiteOuN.

How to create "public string array" from parameter as array?

I have this code:
public static void SendDataToES(String startTimestamp, String startDate, String bid_x, String ask_x)
{
var tem_ehm = new Pre_Market
{
timestamp = startTimestamp,
date = startDate,
bid = bid_x,
ask = ask_x
};
}
class Pre_Market
{
public string x_ric { get; set; }
public string ask { get; set; }
public string bid { get; set; }
public string date { get; set; }
public string timestamp { get; set; }
}
.
But in the future, it will have parameters as Array.
public static void SendDataToES(String startTimestamp, String startDate, String bid_x, String ask_x, IList nameABC, String[] getABCs)
which nameABC[] has value A,B,C and getABC[] has value 1,2,3 so I would like to create in class Pre_Market as Array
public string[] A { get; set;}
public string[] B { get; set;}
public string[] C { get; set;}
Not sure below is working fine ?
for ( int i = 0 ; i < nameABC.Count(); i++ )
{
public string[] nameABC[i] { get; set; }
}
so that the below is available ?
var tem_ehm = new Pre_Market
{
timestamp = startTimestamp,
date = startDate,
bid = bid_x,
ask = ask_x,
A = getABC[0],
B = getABC[1],
C = getABC[2]
};
Updated ! Below is working fine on my side.
var temp_ehm = new Pre_Market
{
timestamp = startTimestamp,
date = startDate,
fids = new Dictionary<string, string>(),
};
for (int i = 0; i < nameFIDs.Count() - 1; i++)
{
temp_ehm.fids.Add(nameFIDs[i], get_FIDs[i]);
}
"fids in temp_ehm can be added" that’s news to me!
If you are ok with using an anonymous class instead of Pre_Market, then You can build up your object structure in JSON ( building a string is easy ), and then use a JSON deserializer (install NewtonSoft.JSON via NuGet) to convert it to an object
Here how you may want to generate your JSON string
string jsonStr = "{ timestamp = \"" + startTimestamp + "\"," +
"date = \"" + startDate + "\"," +
"bid = \"" + bid_x + "\"," +
"ask = \"" + ask_x + "\"";
for ( int i = 0 ; i < nameABC.Count(); i++ )
{
jsonStr += "," + nameABC[i] + " = \"" + getABCs[i] + "\""
}
jsonStr += "}";
A simple solution would be to use a dictionary.
public static void SendDataToES(String startTimestamp, String startDate, String bid_x, String ask_x, IList<string> nameABC, string[] getABCs)
{
var tem_ehm = new Pre_Market
{
timestamp = startTimestamp,
date = startDate,
bid = bid_x,
ask = ask_x,
ABCs = new Dictionary<string, string>()
};
int i = 0;
foreach (string name in nameABCs)
tem_ehm.Add(name, getABCs[i++];
// access the ABCs like so:
string A = tem_ehm.ABCs["A"];
string B = tem_ehm.ABCs["B"];
string C = tem_ehm.ABCs["C"];
}
class Pre_Market
{
public string x_ric { get; set; }
public string ask { get; set; }
public string bid { get; set; }
public string date { get; set; }
public string timestamp { get; set; }
public Dictionary<string, string> ABCs { get; set; }
}

Overload error when adding objects to list

I have written a web service and constructor that adds objects to my list. I am getting an error that makes no sense to me because I am passing in the 3 parameters I should be passing in.
The error is:
There is no argument given that corresponds to the required formal
parameter 'myArticleID' of
'MainPage.GetTileDetails.GetTileDetails(string, string, int)'
Here is my code:
Web Service:
[OperationContract]
List<ViewDetails> ViewDetails();
[DataContract]
public class ViewDetails
{
[DataMember]
public string TitleView { get; set; }
[DataMember]
public string BodyView { get; set; }
[DataMember]
public int ArticleID { get; set; }
public ViewDetails() { }
public ViewDetails(string myTitleView, string myBodyView, int myArticleID)
{
this.TitleView = myTitleView;
this.BodyView = myBodyView;
this.ArticleID = myArticleID;
}
}
Project where i am using web service
public async void ViewData()
{
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
List<GetTileDetails> tileList = new List<GetTileDetails>();
var res = await client.ViewDetailsAsync();
for (int i = 0; i < res.Count; i++)
{
tileList.Add(new GetTileDetails(res[i].TitleView, res[i].BodyView.Substring(0, 170) + " ..."), res[i].ArticleID);
}
tileGridView.ItemsSource = tileList;
}
public class GetTileDetails
{
public string TitleView { get; set; }
public string BodyView { get; set; }
public int ArticleID { get; set; }
public GetTileDetails() { }
public GetTileDetails(string myTitleView, string myBodyView, int myArticleID)
{
this.TitleView = myTitleView;
this.BodyView = myBodyView;
this.ArticleID = myArticleID;
}
}
Can anyone tell me why I am getting that error? I am passing in (string, string, int)....
Replace this line:
tileList.Add(new GetTileDetails(res[i].TitleView, res[i].BodyView.Substring(0, 170) + " ..."), res[i].ArticleID);
with this one:
tileList.Add(new GetTileDetails(res[i].TitleView, res[i].BodyView.Substring(0, 170) + " ...", res[i].ArticleID));
Note you have a misplaced ) right after " ...").

how to get Json nested properties to primary one

I have below scenario:
This is my class structure :
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public System.Collections.ObjectModel.Collection<Likes> Likes { get; set; }
}
public class Likes
{
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
}
When I serialize object of User class then it will generate the below json string :
{"FirstName":"Naresh",
"LastName":"Parmar",
"Likes": [{"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"}]
}
I want to generate above json string like below:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
I want the nested properties as primary one.
Any help would be appreciated.
Thanks in advance..
EDIT:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket,Chess,Football",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
It's really bad practice, since the code i'll post bellow doesn't have great maintainability, however if that's what you looking for, you can use this. Another class that have the format that you'd like, and have a method that adds a list of likes to the format you've required. That the class you should serialize to JSON:
class NestedUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
public void AddLikes(System.Collections.ObjectModel.Collection<Likes> likes)
{
foreach (Likes like in likes)
{
Sport += like.Sport + ",";
Music += like.Music + ",";
Food += like.Food + ",";
Place += like.Place + ",";
}
if (Sport != string.Empty)
{
Sport = Sport.Substring(0, Sport.Length - 1);
}
if (Music != string.Empty)
{
Music = Music.Substring(0, Music.Length - 1);
}
if (Food != string.Empty)
{
Food = Food.Substring(0, Food.Length - 1);
}
if (Place != string.Empty)
{
Place = Place.Substring(0, Place.Length - 1);
}
}
}
Since it's not only limited to Likes objects I'd suggest using dynamic objects. So the User class I propose is as follows:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public dynamic Details { get; set; }
public User()
{
Details = new ExpandoObject();
}
public void AddSingleDetail(string key, string value)
{
var dict = this.Details as IDictionary<string, Object>;
if (dict.ContainsKey(key))
{
dict[key] += "," + value;
}
else
{
dict[key] = value;
}
}
public void AddDetails(object detailsObject)
{
var type = detailsObject.GetType();
foreach (var prop in type.GetProperties())
{
AddSingleDetail(prop.Name, prop.GetValue(detailsObject).ToString());
}
}
}
You can use it for adding single proerpties or adding an object as a whole. I used reflection to get all the property name and values and add them to the user details.
Sample usage:
static void Main(string[] args)
{
var user1 = new User() { FirstName = "Homer", LastName = "Simpson" };
user1.AddSingleDetail("Sport", "Bowling");
user1.AddSingleDetail("Sport", "Sleeping");
user1.AddSingleDetail("Food", "Donut");
user1.AddSingleDetail("Music", "Rock");
string flattenedHomer1 = ConvertUserToFlattenedJson(user1);
var user2 = new User() { FirstName = "Homer", LastName = "Simpson" };
var likes1 = new Likes() { Food = "Donut", Music = "Rock", Place = "Springfield", Sport = "Bowling" };
var likes2 = new Likes() { Food = "Steaks", Music = "Metal", Place = "Evergreen Terrace", Sport = "Sleeping" };
var proStuff = new ProfessionalStuff() { Title = "Boss" };
user2.AddDetails(likes1);
user2.AddDetails(likes2);
user2.AddDetails(proStuff);
string flattenedHomer2 = ConvertUserToFlattenedJson(user2);
}
And the method performing the JSON conversion is:
public static string ConvertUserToFlattenedJson(User u)
{
dynamic flatUser = new ExpandoObject();
flatUser.FirstName = u.FirstName;
flatUser.LastName = u.LastName;
var dict = u.Details as IDictionary<string, Object>;
foreach (var like in dict)
{
((IDictionary<string, Object>)flatUser)[like.Key] = like.Value;
}
string json = Newtonsoft.Json.JsonConvert.SerializeObject(flatUser);
return json;
}
In my sample above user2 is converted to the following JSON string which I believe is what you are looking for:
{
"FirstName": "Homer",
"LastName": "Simpson",
"Sport": "Bowling,Sleeping",
"Music": "Rock,Metal",
"Food": "Donut,Steaks",
"Place": "Springfield,Evergreen Terrace",
"Title": "Boss"
}
While concatenating strings you can check for null or duplicate values. I didn't handle that part.
For the sake of completeness, here's the ProfessionalStuff class I made up:
public class ProfessionalStuff
{
public string Title { get; set; }
}
Hope this helps.

Complex type mapping via linq to xml

I have a list of contacts in XML file.
Each contact have a few properties and mdpr:connection in it.
Connection is separate object.
I read this list and get all contacts to a list with standard proeprties but how to map this Connection to object.
<?xml version="1.0" encoding="UTF-8"?>
<mdpr:Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mdpr="http://...">
<mdpr:contactList>
<mdpr:contact ID="{123456}" classID="Customer">
<mdpr:Name>data1</mdpr:Name>
<mdpr:TransportCode>data2</mdpr:TransportCode>
<mdpr:connection connectionIndex="0" fromID="{12345}" toID="{123456}">
<mdpr:status>1-5</mdpr:status>
<mdpr:startDate>2012-03-13T10:23:00Z</mdpr:startDate>
<mdpr:endDate>2013-03-13T13:44:00Z</mdpr:endDate>
</mdpr:connection>
</mdpr:contact>
</mdpr:contactList>
...
Classes:
public class Contact
{
public string Name { get; set; }
public string TransportCode { get; set; }
public Connection Connection { get; set; }
public TransportPlan()
{
this.Connection = new Connection();
}
}
public class Connection
{
public string status{ get; set; }
public string startDate{ get; set; }
public string endDate { get; set; }
}
Code to read data:
XNamespace mdpr = "http://...";
var contacts = from c in xdoc.Root.Element(mdpr + "contactList")
.Elements(mdpr + "contact")
select new Contact {
TransportCode = (string)c.Element(mdpr + "TransportCode"),
Name = (string)c.Element(mdpr + "Name")
};
So the question is how to read mdpr:connection?
You can access the elements directly by adding another '.Element'. I added a variable for better readability.
var contacts = from c in xdoc.Element(mdpr + "Data")
.Element(mdpr + "contactList")
.Elements(mdpr + "contact")
let contact = c
let connection = contact.Element(mdpr + "connection")
select new Contact
{
TransportCode = (string)contact.Element(mdpr + "TransportCode"),
Name = (string)contact.Element(mdpr + "Name"),
Connection = new Connection
{
status = (string)connection.Element(mdpr + "status"),
startDate = (string) connection.Element(mdpr + "startDate"),
endDate = (string)connection.Element(mdpr + "endDate"),
},
};
If you want to allow multiple connections (in order to make the scenario more complex)
public class Contact
{
public string Name { get; set; }
public string TransportCode { get; set; }
public List<Connection> Connections { get; set; }
}
Code to parse multiple connections
var contacts = from c in xdoc.Element(mdpr + "Data")
.Element(mdpr + "contactList")
.Elements(mdpr + "contact")
let contact = c
let connections = contact.Elements(mdpr + "connection")
select new Contact
{
TransportCode = (string)contact.Element(mdpr + "TransportCode"),
Name = (string)contact.Element(mdpr + "Name"),
Connections = connections.Select( connection =>
new Connection
{
status = (string)connection.Element(mdpr + "status"),
startDate = (string) connection.Element(mdpr + "startDate"),
endDate = (string)connection.Element(mdpr + "endDate"),
}).ToList(),
};

Categories