Updating Field in RavenDB Document - c#

Good day,
I have a RavenDB JSON Document in which one field ("Info") contains a string that looks like this:
"{\"value1\":\"9\", \"value2\": \"dog\", ....}"
I would like to remove the escaping "\" characters so it will be recognized as a JSON List by RavenDB.
However, I have tried updating the Documents with
newString = oldString.Replace("\\", "") ,
newString = oldString.Replace(#"\", "")
and newString = oldString.Trim(new Char[] { #"\" })
but it does not work. After applying these above mentioned methods the string looks unchanged.
Please see below the full code:
while(true)
{
var result = session.Query<Documents>()
.Take(1000).Skip(i)
.ToList();
if (result.Count == 0)
break;
foreach (var r in result)
{
string rInfo = r.Info.ToString();
rInfo = rInfo.Replace("\\", "");
PATCHED_Doc r_Doc = new PATCHED_Doc()
{
Info = rInfo,
Value = "test",
Id = r.Id,
Date = r.Date,
};
session.Store(r_Doc);
session.SaveChanges();
}
session.SaveChanges();
i += result.Count;
}
public class PATCHED_Doc
{
public string Info { get; set; }
public string Value { get; set; }
public int Id { get; set; }
public string Date { get; set; }
}
Thank you in advance for helping.

You need to Parse the JSON into an object and then hand it over to Raven DB. Strings are treated as strings. Use JSON.NET library to parse it into Anonymous objects. Change your Info property to type of object. Then Assign the anonymous object to the Info property.

Related

C# dynamic class - how to preserved the var name from serialize output

The variable name with # prefix changed after serialize due C# naming. How to prevent this?
//assignment of object value with #Timestamp
List<dynamic> Documents = new List<dynamic>();
Documents.Add( new { Index = ""index-name-test", Type = "doc", Id = g.ToString(),
Title = "title1", #Timestamp = DateTime.UtcNow });
foreach (var doc in Documents)
{
var json = JsonConvert.SerializeObject(new { Documents= doc });
}
as in the json value, it contain
"{\"Documents\":{\"Index\":\"index-name-test*\",\"Type\":\"doc\",\"Id\":\"76134434-2ed0-48df-9034-841b386a0dbc\",\"Title\":\"title1\",\"Timestamp\":\"2019-04-14T15:50:33.596931Z\"}}"
{"Documents":{"Index":"index-name-test*","Type":"doc","Id":"76134434-2ed0-48df-9034-841b386a0dbc","Title":"title1","Timestamp":"2019-04-14T15:50:33.596931Z"}}
How to make Timestamp become #Timestamp ?
In C#, prefixing a variable name with # is just a way to allow you to use reserved words as variable names. For example, you can do this:
var #class = "foo";
If you don't use a # you will get a compiler error. As such, when you serialise your dynamic objects, the variable name is still Timestamp. The best option would be to use a concrete class to store your data. Not only can you then control the names when serialising, but you get compile time type safety and it's far quicker than using dynamic (every time you use dynamic a kitten dies!)
So I would create two classes like this:
//Root class so you don't need to serialise an anonymous type and can easily deserialise later
public class Root
{
public List<Document> Documents { get; set; }
}
public class Document
{
public string Index { get; set; }
public string Type { get; set; }
public string Id { get; set; }
public string Title { get; set; }
//This attribute controls the JSON property name
[JsonProperty("#Timestamp")]
public string Timestamp { get; set; }
}
And serialise something like this:
var root = new Documents();
root.Documents = new List<Document>
{
new Document
{
Index = ""index-name-test",
Type = "doc",
Id = g.ToString(),
Title = "title1",
Timestamp = DateTime.UtcNow
}
};
var json = JsonConvert.SerializeObject(root);

LINQ convert SQL server Datetime to string using a DTO

I've been tasked to add a page to an API that we didn't build but are tasked to work on. The API is using C# MVC5. I don't really know MVC5, and but I'm attempting to keep the same design pattern that the rest of the API is using. I have to add functionality that will allow a user on the front end to upload a file to a server that will be processed for inserting into a SQL Server DB. This functionality will also return a list of all the files names and status of the imported files from a table in the DB.
The issue I'm having is converting a Datetime to a string in the LINQ query that is pulling the list of files.
I've attempted to try using this answer LINQ convert DateTime to string, but with no luck.
This is what I have so far, I've marked the line that is causing the issue:
[Route("ImportLogs", Name ="GetImportLogs")]
[HttpGet]
[ResponseType(typeof(List<IHttpActionResult>))]
public IHttpActionResult GetImportLogs()
{
var query =
from dbitem in db.ImportLogs
orderby dbitem.import_log_id
select new ImportLogDto()
{
Id = dbitem.import_log_id,
FileName = dbitem.import_file_name,
ImportTimeStamp = dbitem.import_timeStamp,
ImportStatus = dbitem.import_status,
ImportMessage = dbitem.import_message
};
query.ToList()
.Select(o => new ImportLogDto
{
Id = o.Id,
FileName = o.FileName,
ImportMessage = o.ImportMessage,
ImportStatus = o.ImportStatus,
ImportTimeStamp = o.ImportTimeStamp.ToString() //PROBLEM LINE
});
return Ok(query);
}
The error that I'm getting is
Cannot implicitly convert type 'string' to 'System.DateTime'
What am doing wrong? Any help would be appreciated. TIA.
EDIT:
Here is the DTO:
public class ImportLogDto
{
public int Id { get; set; }
public string FileName { get; set; }
public DateTime ImportTimeStamp { get; set; }
public string ImportStatus { get; set; }
public string ImportMessage { get; set; }
}
You are trying to assign a string into a DateTime so you get that exception. If you want to cast it to a string change your model as follows:
public class ImportLogDto
{
public int Id { get; set; }
public string FileName { get; set; }
public string ImportTimeStamp { get; set; } // Changed type
public string ImportStatus { get; set; }
public string ImportMessage { get; set; }
}
And then your query:
var query = (from dbitem in db.ImportLogs
orderby dbitem.import_log_id
select new {
Idbitem.import_log_id,
dbitem.import_file_name,
dbitem.import_timeStamp, // Still DateTime
dbitem.import_status,
dbitem.import_message
}).AsEnumerable(); // Retrieved from Database
.Select(o => new ImportLogDto
{
Id = o.import_log_id,
FileName = o.import_file_name,
ImportMessage = o.import_message,
ImportStatus = o.import_status,
ImportTimeStamp = o.import_timeStamp.ToString() // Changes to string
});
If you wnat to change the format of the DateTime for the API then then use its overload of ToString and specify a format:
ImportTimeStamp = o.ImportTimeStamp.ToString("dd/MM/yyyy HH24:MI:ss")
For more on the overload read: Custom Date and Time Format Strings
Your types are already DateTime, and since these types are tied to the backing data* you probably shouldn't change them. But where you return the values on the API you can really return anything you want. So an anonymous type could be a quick solution:
.Select(o => new // <--- notice no type definition here
{
Id = o.Id,
FileName = o.FileName,
ImportMessage = o.ImportMessage,
ImportStatus = o.ImportStatus,
ImportTimeStamp = o.ImportTimeStamp.ToString()
})
The compiler will know based on the type returned by .ToString() that you want ImportTimeStamp to be a string. You can then add formatters to .ToString() to customize the output however you like.
*If your DTO isn't actually tied to the database then you can change the type there from DateTime to string, of course. It's not really clear from the context of the code shown whether these are data DTOs or application DTOs.

How to handle bad Json response in C# using JsonConvert

I am using a web service to get response and found the Json is not in the right format. Please see the below sample.
The Object structure is :
public class Action
{
public string serialNumber { get; set; }
public string method1 { get; set; }
public string recipient1 { get; set; }
public string notifyon1 { get; set; }
}
We having a field "recipient1" which has value "1#test.com,2#test.com,3#test.com" then the api response the json as below.
Bad json response :
{"serialNumber": "2471",
"method1": "email",
"recipient1": "1#test.com",
"2#test.com": "",
"3#test.com": "",
"notifyon1": "warning",
"critical": ""}
Which is supposed to be :
{"serialNumber": "2471",
"method1": "email",
"recipient1": "1#test.com,2#test.com,3#test.com",
"notifyon1": "warning,critical"}
First I was trying to using regex to convert these emails values to the right field. But then I found it is happened for all the value which include comma "," . Such as ”Notifyon1“ in the above sample.
Now I am thinking if there is any way I can do parse the json, when it find "2#test.com" then check the Object, if it is not a property then put it as a value into previous field "recipient1".
Thanks for all your help.
This will work regardless of empty values in the properties.
using Newtonsoft.Json;
private Action HandleBadJson(string badJson)
{
Dictionary<string, string> dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(badJson);
Action act = new Action();
List<string> propertyNames = act.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Select(p => p.Name).ToList();
string currentProperty = "";
foreach (var keyValPair in dictionary)
{
if (propertyNames.Contains(keyValPair.Key))
{
currentProperty = keyValPair.Key;
act.GetType().GetProperty(currentProperty).SetValue(act, keyValPair.Value);
continue;
}
else
{
var currentValue = act.GetType().GetProperty(currentProperty).GetValue(act, null);
string value = currentValue + "," + keyValPair.Key;
value = value.Trim(',');
act.GetType().GetProperty(currentProperty).SetValue(act, value);
}
}
return act;
}

Deserialise JSON and access content using Linq to JSon

I have the following JSON stored in a cookie that I wish to parse:
{"package":[{"id":"5054","nodeId":"3286"},{"id":"8888","nodeId":"7777"}], "hotel":[{"id":"3421","nodeId":"1234"},{"id":"8748","nodeId":"2435"}], "activity":[{"id":"5054","nodeId":"3286"},{"id":"8888","nodeId":"7777"},{"id":"2131","nodeId":"2342"}]}
I understand from the accepted answer on this question Deserializing JSON to .NET object using Newtonsoft (or LINQ to JSON maybe?) that you can use the following code to access individual objects within JSON notation:
JToken token = JObject.Parse(stringFullOfJson);
int page = (int)token.SelectToken("page");
int totalPages = (int)token.SelectToken("total_pages");
I've therefore adapted this into my code as follows:
HttpCookie cookie = Request.Cookies.Get("wishlist");
string JSONstring = string.Empty;
string nodeId = string.Empty;
if (cookie != null)
{
JSONstring = cookie.Value;
JToken token = JObject.Parse(JSONstring);
}
I now wish to only retreive the package array for example and loop through each of the items in this array and output the ids in the following format:
5054,8888
From the example code I sort of came up with the following approach but i'm not sure if i'm proceeding in the right direction.
JObject obj = JObject.Parse(JSONstring);
JArray packages = (JArray)obj["package"];
What is the best way of specifying one of the arrays eg. hotel, package , looping through their contents and outputting each of the id nodes that are found? The nodeId will always be numeric but the id could be a string or an int so this adds another layer of complication.
Any help would be greatly appreciated and I apologise if this is a sumwhat stupid or easy question however I have jsut started working with .Net and OO so some of the concepts are still a bit foggy.
Here's How I would Do This, I'd Create the classes required to Deserialize the JSON :-
public class JSONCookie
{
public Package[] package { get; set; }
public Hotel[] hotel { get; set; }
public Activity[] activity { get; set; }
}
public class Package
{
public string id { get; set; }
public string nodeId { get; set; }
}
public class Hotel
{
public string id { get; set; }
public string nodeId { get; set; }
}
public class Activity
{
public string id { get; set; }
public string nodeId { get; set; }
}
Now, I would Create a method that actually does the deserialising :-
public JSONCookie GetJSONCookieResponse()
{
try
{
// Add your own code that gets the Response Here.
// string response = "{"package":[{"id":"5054","nodeId":"3286"},{"id":"8888","nodeId":"7777"}], "hotel":[{"id":"3421","nodeId":"1234"},{"id":"8748","nodeId":"2435"}], "activity":[{"id":"5054","nodeId":"3286"},{"id":"8888","nodeId":"7777"},{"id":"2131","nodeId":"2342"}]}";
//return new JsonSerializer().Deserialize<JSONCookie>(new JsonTextReader(new StringReader(response)));
}
catch
{
return null;
}
}
From the JSONCookie Object that is returned, you can then use LINQ to pick out what you need like follows :-
x.package.Select(p=>p.id);
After a lot of trawling Google, this is the easiest solution I have come up with:
HttpCookie cookie = Request.Cookies.Get("wishlist");
string JSONstring = string.Empty;
string nodeId = string.Empty;
string test = string.Empty;
if (cookie != null)
{
JSONstring = cookie.Value;
JObject obj = JObject.Parse(JSONstring);
JArray packages = (JArray)obj["package"];
foreach (var item in packages.Children()){
var properties = item.Children<JProperty>();
var idElement = properties.FirstOrDefault(x => x.Name == "id");
var myElementValue = idElement.Value;
test = test + myElementValue + ",";
}
}
This will output all ids in the packages array in a CSV format (with a trailing ,)

ForEach loop not changing property of class

I've seen a couple questions about this, and done some research.
My understanding is that when you run a foreach on IEnumerable: if T is a Reference Type (e.g. Class) you should be able to modify properties of the object from within the loop. If T is a value type (e.g. Struct) this would not work since the iteration variable would be a local copy.
I am working on a Windows Store app with the following code:
My Class:
public class WebResult
{
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string DisplayUrl { get; set; }
public string Url { get; set; }
public string TileColor
{
get
{
string[] colorArray = { "FFA200FF", "FFFF0097", "FF00ABA9", "FF8CBF26",
"FFA05000", "FFE671B8", "FFF09609", "FF1BA1E2", "FFE51400", "FF339933" };
Random random = new Random();
int num = random.Next(0, (colorArray.Length - 1));
return "#" + colorArray[num];
}
}
public string Keywords { get; set; }
}
The Code:
IEnumerable<WebResult> results = from r in doc.Descendants(xmlnsm + "properties")
select new WebResult
{
Id = r.Element(xmlns + "ID").Value,
Title = r.Element(xmlns + "Title").Value,
Description = r.Element(xmlns +
"Description").Value,
DisplayUrl = r.Element(xmlns +
"DisplayUrl").Value,
Url = r.Element(xmlns + "Url").Value,
Keywords = "Setting the keywords here"
};
foreach (WebResult result in results)
{
result.Keywords = "These, are, my, keywords";
}
if (control is GridView)
{
(control as GridView).ItemsSource = results;
}
Once the results get displayed the "Keywords" property is "Setting the keywords here". If I put a break point in the foreach loop I can see that the results object is not getting modified...
Any ideas as to what is going on? Am I just missing something obvious? Does IEnumerable behave differently in .NET For Windows Store Apps?
This is known as deferred execution; results is a query that is executed every time you iterate over it. In your case it's evaluated twice, once in the for loop, and a second time when it's databound.
You can verify this by doing something like this
var results2 = results.ToList();
foreach (WebResult result in results2)
{
result.Keywords = "These, are, my, keywords";
}
if (control is GridView)
{
(control as GridView).ItemsSource = results2;
}
You should see that your changes persisted.

Categories