How to flatten class containing an IEnumerable of a related class - c#

I have the following class:
public class OrgAlertList
{
public string CustMailName { get; set; }
/// <summary>
/// Gets all the alerts that apply to this customer.
/// </summary>
public virtual IEnumerable<OrgAlertSummary> Alerts { get; set; }
}
That contains a property (named Alerts) that is an IEnumerable of my second class:
public class OrgAlertSummary
{
/// <summary>
/// Message detailing the alert for the user.
/// </summary>
public string Message { get; set; }
/// <summary>
/// Message detailing how to fix alert.
/// </summary>
public string ActionMessage { get; set; }
}
The Alerts property in the OrgAlertList can contain zero to many OrgAlertSummary items.
I need to write a Lambda expression, or use a LINQ query, to flatten the classes into a new type that has the CustMailName, Message, and ActionMessage in it for each OrgAlertList item where the Alerts property contains at least one OrgAlertSummary item. Can anyone help with this?

Try this: (untested)
var q = from orgAlert in myOrgAlertList
from orgAlertSummary in orgAlert.Alerts
select new { orgAlert.CustomMailName,
orgAlertSummary.Message,
orgAlertSummary.ActionMessage};
Assuming myOrgAlertList is some sort of IEnumerable<OrgAlertList>
This query will create an anonymous type with fields named CustomMailName, Message, and ActionMessage. If you intend to export this resulting list to other modules, it's recommended to define your own class and create it in the select instead of using an anonymous type.

Related

How can I make my class act like a Guid when used in Linq?

I am using Cosmosdb with .net CORE 2.2 and the Cosmosdb SQL SDK. By default cosmosdb will assign every documents 'Id' property as a Guid. But the Id alone is not enough to directly read the document, you must also know its partition. So I created a class named CosmosGuid that contains a Id property(Guid) and a PartitionKey property(string). The ToString() is overridden to call .ToString("N") on the Guid to remove the dashes and it appends the PartitionKey to the end. The problem im having is when I use the CosmosGuid in Linq, the generated SQL will contain a json version of CosmosGuid, I really need it to just be a string. I can call .ToString() and that will produce the desired result, but im afraid another developer will use my class in a Linq expression and it fail for no known reason. When I save the CosmosGuid I created a custom newtonsoft converter to call ToString() when it saves and to call .Parse(string) when it reads. When you compare two Guids in Linq the generated SQL comes out to a string, but when I compare two CosmosGuid it creates a json string of my class. How can I make my class act like a Guid?
I have already attempted to implement all the same Interfaces as the Guid. The closes I have came was implementing 'IEnumerable' and in the GetComparer() I returned:
new string[] { this.ToString() }.GetEnumerator();
The code produced was perfect, but it kept putting my string surrounded with brackets[].
here is an example:
SELECT VALUE root FROM root WHERE (root['id'] = ['9a9dbbd5f78143c48b16f780c7ceaa4011'])
This is the CosmosGuid class, I figure id post the full class since its not very large and it may be useful to some.
public class CosmosGuid
{
// This is the unique Id of the entity
public Guid Guid { get; set; }
// This is the partition key where the entity lives
public string PartitionKey { get; set; }
// This is the unique Id of the Document that contains the entity
public Guid? ParentGuid { get; set; }
// This is the PartitionKey of the Document that contains the entity
public string ParentPartitionKey { get; set; }
/// <summary>
/// Parses a CosmosGuid string into a new CosmosGuid
/// </summary>
/// <param name="cosmosGuid"></param>
public CosmosGuid(string cosmosGuid)
{
ParentGuid = null;
ParentPartitionKey = null;
try
{
var parsed = cosmosGuid.Split('-');
// We can accuratly parse the guid from the string by always grabing the first 32 characters.
// The characters after the first 32 are the PartitionKey.
// https://stackoverflow.com/a/4458925
// Guid.NewGuid().ToString("N") => 32 characters (digits only, no dashes)
Guid = Guid.Parse(parsed[0].Substring(0, 32));
PartitionKey = parsed[0].Substring(32, parsed[0].Length - 32);
if (parsed.Length == 2)
{
ParentGuid = Guid.Parse(parsed[1].Substring(0, 32));
ParentPartitionKey = parsed[1].Substring(32, parsed[1].Length - 32);
}
}
catch (Exception ex)
{
throw new Exception("The Id of the document is not a properly formatted CosmosGuid.", ex);
}
}
/// <summary>
/// Generates a new Guid and appends the PartitionKey. This is used for Documents.
/// </summary>
/// <param name="partitionKey"></param>
/// <returns></returns>
public static CosmosGuid NewCosmosGuid(string partitionKey)
{
return new CosmosGuid($"{ShortenGuid(Guid.NewGuid())}{partitionKey}");
}
/// <summary>
/// Generates a new Guid and appends the PartitionKey as well as the Parent Guid and Parent PartitionKey. This is used for Subdocuments.
/// </summary>
/// <param name="parent"></param>
/// <param name="partitionKey"></param>
/// <returns></returns>
public static CosmosGuid NewCosmosGuid(CosmosGuid parent, string partitionKey)
{
return new CosmosGuid($"{ShortenGuid(Guid.NewGuid())}{partitionKey}-{ShortenGuid(parent.Guid)}{parent.PartitionKey}");
}
/// <summary>
/// Returns only the Parent CosmosGuid. If there is no parent the value returned will be null.
/// </summary>
public CosmosGuid Parent
{
get
{
if (ParentGuid != null && ParentPartitionKey != null)
return new CosmosGuid($"{ShortenGuid((Guid)ParentGuid)}{ParentPartitionKey}");
else
return null;
}
}
/// <summary>
/// Parses a CosmosGuid string into a new CosmosGuid.
/// </summary>
/// <param name="cosmosGuid"></param>
/// <returns></returns>
public static CosmosGuid Parse(string cosmosGuid)
{
return new CosmosGuid(cosmosGuid);
}
/// <summary>
/// Generates a CosmosGuid formatted string.
/// </summary>
/// <returns></returns>
public override string ToString()
{
if (ParentGuid == null)
return $"{ShortenGuid(Guid)}{PartitionKey}";
else
return $"{ShortenGuid(Guid)}{PartitionKey}-{ShortenGuid((Guid)ParentGuid)}{ParentPartitionKey}";
}
/// <summary>
/// Removes the dashes from a Guid
/// </summary>
/// <param name="guid"></param>
/// <returns></returns>
private static string ShortenGuid(Guid guid)
{
// Just remove dashes from the guid to shorten it some.
// More can be done here if you wish but make sure the guid uniqueness isnt compromised.
return guid.ToString("N");
}
public static bool operator ==(CosmosGuid obj1, CosmosGuid obj2)
{
return obj1?.ToString() == obj2?.ToString();
}
public static bool operator !=(CosmosGuid obj1, CosmosGuid obj2)
{
return obj1?.ToString() != obj2?.ToString();
}
}
If a developer where to use the CosmosGuid like so it would fail to work, because the SQL generated is a Json version of the class. (the Id is also a CosmosGuid):
var cosmosGuid = CosmosGuid.Parse("6bec688a0aca477c8175c09162b7a9b411");
var result = await Client.CreateDocumentQuery<MyClass>(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), options)
.Where(x => x.Id == cosmosGuid)
.AsDocumentQuery();
This is the sql generated
SELECT VALUE root FROM root WHERE (root['id'] = {'Guid':'6bec688a-0aca-477c-8175-c09162b7a9b4','PartitionKey':'11','ParentGuid':null,'ParentPartitionKey':null,'Parent':null})
Instead, the developer must call .ToString() everywhere in the code.
var cosmosGuid = CosmosGuid.Parse("6bec688a0aca477c8175c09162b7a9b411");
var result = await Client.CreateDocumentQuery<MyClass>(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), options)
.Where(x => x.Id.ToString() == cosmosGuid.ToString())
.AsDocumentQuery();
This is the Sql generated
SELECT VALUE root FROM root WHERE (root['id'] = '6bec688a0aca477c8175c09162b7a9b411')
If I remove the CosmosGuid and revert back to using just a Guid as the Id property the SQL generated by the Cosmosdb SDK works fine. How can I make my class act like a .net Guid when used in Linq?
For LINQ to objects:
You can overload the == operator on your CosmosGuid class, see operator keyword.
Also, you could implement IEquatable<Guid> and use the .Equals() instead:
public class CosmosGuid : IEquatable<Guid>
{
....
public bool Equals(Guid other) {
return this.Guid == other;
}
}
.Where(x => cosmosGuid.Equals(x.Id))

Attributes on Field in Class

I want to get a list of fields with an Attribute Sync.Field on each of the field in the class. The field can / cannot have the attribute of Sync.Field
I have been trying the following, but having trouble getting the custom attribute for each field.
FieldInfo[] fiClass = typClass.GetFields();
FieldInfo[] lst = fiClass
.Where(c => c.CustomAttribute().GetType() == typeOf(Sync.Field))
.ToList();
I have a generic collection class, which uses a data class to match an SNMP table with data class fields. Like JsonProperty matches deserialised values to properties. In the same way I define a SNMPPropertyAttribute. The attribute itself is
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
sealed class SNMPPropertyAttribute : Attribute
{
public SNMPPropertyAttribute(string propertyOID) => PropertyOID = new ObjectIdentifier(propertyOID);
public ObjectIdentifier PropertyOID { get; }
}
When in the table constructor, I'm making a dictionary of data fiels and their OIDs from the attribute:
public SNMPTableEntity()
{
snmpPoperties = new Dictionary<ObjectIdentifier, PropertyInfo>();
foreach (PropertyInfo myProperty in GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{
CustomAttributeData snmpAttribure = myProperty.CustomAttributes.Where(x => x.AttributeType == typeof(SNMPPropertyAttribute)).FirstOrDefault();
if (snmpAttribure != null)
snmpPoperties.Add(new ObjectIdentifier((string)snmpAttribure.ConstructorArguments[0].Value), myProperty);
}
}
It looks similar to what are you trying to acheive, so hopefully it helps. But the difference, is that I'm using properties, not fields. Not sure if it makes a big difference, but...
There is an example of using:
public class InterfaceTableEntity : SNMPTableEntity
{
/// <summary>
/// A unique value for each interface. Its value ranges between 1 and the value of ifNumber. The value for each interface must remain constant at least from one re-initialization of the entity's network management system to the next re- initialization.
/// </summary>
[SNMPProperty("1.3.6.1.2.1.2.2.1.1")]
protected Integer32 ifIndex { get; set; }
/// <summary>
/// A textual string containing information about the interface. This string should include the name of the manufacturer, the product name and the version of the hardware interface.
/// </summary>
[SNMPProperty("1.3.6.1.2.1.2.2.1.2")]
protected OctetString ifDescr { get; set; }
/// <summary>
/// The type of interface, distinguished according to the physical/link protocol(s) immediately `below' the network layer in the protocol stack.
/// </summary>
[SNMPProperty("1.3.6.1.2.1.2.2.1.3")]
protected Integer32 ifType { get; set; }
}
If you have the FieldInfo, you can get an instance of its attribute using this code:
var attr = fieldInfo.GetCustomAttributes().OfType<Sync.FieldAttribute>().SingleOrDefault();
See my example on DotNetFiddle.

Calling a function on Type Parameter in Generic Class C#

How can we call a function that is defined abstract in a generic base class.
I have a generic
class Class1<T> where T : class, new()
and multiple classes which derive from it like
Class2: Class1<Class2>
Class3: Class1<Class3>
The generic class has 3 functions
1-> accept a dynamic object and puts all the values to corresponding properties in the object of derive
2-> accepts the ID, looks for the corresponding row in database pass the dynamic object to func1 and return the result
3-> a listall function which returns all rows in table
Here is the generic code
public abstract partial class Class1<T> where T : class, new()
{
public static EntityLayout EntityLayout { get; protected set; }
[TypeAttributes(TypeAttributes.Options.IsPrimary, TypeAttributes.Options.IsAutoIncrement)]
/// <summary> Automatically Incremented 64 bit Integer Primary Key
/// represents the Unique ID of each row in Table </summary>
public long ID { get; set; }
/// <summary> Converts the row returned from Database to Object </summary>
/// <param name="row"></param>
/// <returns></returns>
public abstract T GetDetails(dynamic row);
public static T GetDetails(long ID)
{
var row = Shared.SessionWrapper.Current.globaldbcon.QuerySingle("SELECT * FROM ["
+ EntityLayout.ContainerName + "].["
+ EntityLayout.TableName + "] WHERE ID=#0", ID);
if (row != null) return GetDetails(row);
return new T();
}
public static List<T> ListAll()
{
List<T> result = new List<T>();
foreach (var row in Shared.SessionWrapper.Current.globaldbcon.Query("SELECT * FROM ["
+ EntityLayout.ContainerName + "].["
+ EntityLayout.TableName + "]")) result.Add(GetDetails(row));
return result;
}
}
An example class Implementation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Arinsys.Database;
namespace WebApplication1.Models
{
[EntityAttributes(EntityAttributes.Options.TestingEnabled)]
public class Class3 : Class1<Class3>
{
static Class3()
{
EntityLayout.DisplayName = "Users";
}
/// <summary> User ID of the User </summary>
public long UID { get; set; }
/// <summary> User ID of the User if defined in Universal Data Store </summary>
public long UDSID { get; set; }
/// <summary> Login ID of User </summary>
public string LoginID { get; set; }
/// <summary> Registered email of the user. If not set will be set same as LoginID </summary>
public string Registeredemail { get; set; }
[TypeAttributes(TypeAttributes.Options.IsPassword)]
/// <summary> Password of user </summary>
public string Password { get; set; }
/// <summary> A Unique Security Stamp used for activation/deactivation of account or similar intense tasks </summary>
public string SecurityStamp { get; set; }
/// <summary> Timezone ID of the Default Timezone of User </summary>
public string DefaultTimezone { get; set; }
/// <summary> Current Status of User </summary>
public string CurrentStatus { get; set; }
/// <summary> Discriminator which defines the type of user in multi-user heirarchy scenario </summary>
public string UserType { get; set; }
/// <summary> Number of failed login attempts in total or same session depending upon configuration. Resets after Successful Login </summary>
public short FailedAttempts { get; set; }
/// <summary> Date Time of Last Failed Login Attempt in UTC </summary>
public DateTime LastFailedAttempt { get; set; }
/// <summary> Date Time of Last Successful Login in UTC </summary>
public DateTime LastLogin { get; set; }
/// <summary> Creation Date of User Account in UTC </summary>
public DateTime CreationDate { get; set; }
public override Class3 GetDetails(dynamic row)
{
Class3 result = new Class3();
if (row != null)
{
result.ID = Convert.ToInt64(row.ID);
result.UID = Convert.ToInt64(row.UID);
result.UDSID = Convert.ToInt64(row.UDSID);
result.UserType = row.UserType;
result.LoginID = row.LoginID;
result.Password = row.Password;
result.Registeredemail = row.Registeredemail;
result.SecurityStamp = row.SecurityStamp;
result.DefaultTimezone = row.DefaultTimezone;
result.CurrentStatus = row.CurrentStatus;
result.FailedAttempts = Convert.ToInt16(row.FailedAttempts);
result.LastFailedAttempt = Convert.ToDateTime(row.LastFailedAttempt);
result.LastLogin = Convert.ToDateTime(row.LastLogin);
result.CreationDate = Convert.ToDateTime(row.CreationDate);
}
return result;
}
}
}
Its been two weeks searching for the answer everywhere before posting, but couldn't find the solution.
All i want is that ListAll function should call 1st function. Since it's defined abstract i am sure the deriving class has to have an implementation (even though it might be just throw NotImplementException, but implementation is guaranteed)
I first defined the implementation of 1st function in generic class itself through reflection. Though that works, but its very slow, did performance bench-marking by starting/stopping a Stopwatch at start/end of controller action and it took approx 35 seconds for just 100 rows, so it's surely not something for production use.
Points to note
Static cannot be defined abstract
Cannot access instance member from static context
Cant use reflection because of performance issues
Possible Solutions i guess are closest ( but i am unable to understand how to use them in my case)
convert all methods to instance methods and use singleton
using interfaces
define a static method in derived class and assume it will be there in all classes, if i go this way then how to access static method on T in that case
What i want to achieve is that ListAll function should call 1st function accepting a dynamic object.
Some questions which come very close are these, but none of them solves my query.
Stack Overflow Q1 Stack Overflow Q2 Stack Overflow Q3
Looks like the design should be like this
public abstract partial class Class1<T> where T : Class1<T>, new()
{
protected abstract void Load(dynamic row);
private static T GetItem(dynamic row)
{
var item = new T();
if (row != null)
item.Load(row);
return item;
}
public static T GetDetails(long ID)
{
var row = Shared.SessionWrapper.Current.globaldbcon.QuerySingle("SELECT * FROM ["
+ EntityLayout.ContainerName + "].["
+ EntityLayout.TableName + "] WHERE ID=#0", ID);
return GetItem(row);
}
public static List<T> ListAll()
{
List<T> result = new List<T>();
foreach (var row in Shared.SessionWrapper.Current.globaldbcon.Query("SELECT * FROM ["
+ EntityLayout.ContainerName + "].["
+ EntityLayout.TableName + "]")) result.Add(GetItem(row));
return result;
}
}
and the sample implementation
public class Class3 : Class1<Class3> {
{
// ...
protected override void Load(dynamic row)
{
// No need to check for null, it is enforced by the base class
ID = Convert.ToInt64(row.ID);
UID = Convert.ToInt64(row.UID);
// ...
}
}
Basically you explore the Curiously recurring template pattern supported by .NET generic class constraints (T : Class1<T>) to ensure the derived class contains the abstract Load method, while the new T() part is enforced by the new() constraint.

How do I create multiple overloads of CRUD methods? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
If I have a class which represent a mapping to a specific table in my db in somehow.
This class contains about 30 properties.
I have created the CRUD Methods.
And find myself need to another (UPDATE) method which should update just two fields.
What should I do in a good manner with simple example?
Using my exist method, Filling the whole object and update all the fields including my intended two fields? (Useless work)
Create static Method with another name (but I want to keep my method name because it's expressive)! And takes two parameters?
I would go by by creating two separate interface and create overloaded functions for each interface. I would group properties based on usage, like I want status to be updated some time separate from other common properties.
public interface ICommonProperties
{
public string P1{get; set;}
public string P2{get; set;}
public string P3{ get; set; }
}
public interface ITrackable
{
public string Status{get; set;}
}
public class FinalClass : ICommonProperties, ITrackable
{
public string P1{get; set;}
public string P2{get; set;}
public string P3{get; set;}
public string Status{get; set;}
}
public class FinalClassOperations
{
public void Update(FinalClass finalClassInstance) { }; //Updates everything
public void Update(ICommonProperties finalClassInstance) { }; //Updates only ICommonProperties
public void Update(ITrackable finalClassInstance) { }; //updates only Status.
}
Additionally, if you want you can create a separate class for just updating the status, and that would still fit in:
public class Tracker : ITrackable{
public string Status{get; set;}
}
But yes, if the two properties cannot be separated out logically, I would not do that and keep them together.
I would suggest to follow your second option but there is no need to change the name as the number of method parameter will be different on both it's
Let's as walk into few example
I will try to create an similar situation, I hope it's your situation. you can clarify if i got wrongly the question.
CLASSES AND METHOD
/// <summary>
/// CLass to store properties related to database
/// </summary>
class ObjectoA
{
public string A{get; set;}
public string B{get; set;}
public string C{ get; set; }
}
/// <summary>
/// class to call method to update.
///
/// </summary>
class ObjectB
{
/// <summary>
/// update method.
/// I would go with this solution.
/// optionlay you can call the method which receive parameter of object
/// </summary>
/// <param name="A"> Object with properties mapped to database</param>
/// <param name="updatetwoproperties">Optional paramneter to decide which update to run.
/// the default value should be for update that run most. For your need if you want to create an update methods for other
/// two sets of parameter a suggest you create an Enum and pass this enum as optional parameter instead of bool parameter or you
/// can pass as string and map each string value to specific update inside. IF YOU NEED EXAMPLE
/// REPLAY ON COMMENTS</param>
/// <returns></returns>
public bool update(ObjectoA A, bool updatetwoproperties=false)
{
//method implementation
if (updatetwoproperties)
{
//implement a update to all field
}
else
{
//implement update just to two field
}
return true;
}
/// <summary>
/// update method based on parameter to update
/// </summary>
/// <param name="a">this properties is mapped on database</param>
/// <param name="b">this propertie is mapped on database</param>
/// <returns></returns>
public bool update(string a, string b)
{
//method implementation e validate the return value
return true;
}
}
/// <summary>
/// I don't suggest to use this solution because
/// it will add a method on string type while this method isn't related to string
/// I just added here as a workaround for you.
/// </summary>
public static class ObjectC
{
public static bool update(this string a, string b)
{
//implementation of update and validate the return value
return true;
}
}
CALLING METHOD AND EXPLANATION
static void Main(string[] args)
{
ObjectB B = new ObjectB(); //Class with methods
ObjectoA A = new ObjectoA(); //object with properties
#region Using Optional parameter to decide which update to run
//Calling a method to update all columns
B.update(A);
//Calling a method to update two columns
B.update(A, true);
#endregion
#region Using polymorphism to update
//Calling a method to update all columns
B.update(A);
//Update only using paramenter
B.update(A.B, A.C);
#endregion
//NOT RECOMMEND BECAUSE THIS UPDATE ISN'T RELATED TO STRING TYPE
#region Using extension method to update
//Calling a method to update all columns
B.update(A);
//using the extension method on variable type
A.B.update(A.C);
#endregion
//WE COULD USE EXTENSION METHOD ON YOUR OBJECT BUT IT WILL FAIL BECAUSE WE ALREADY AS UPDATE METHOD ON CLASS
//IF YOU WANT TO SEE HOW JUST REPLAY
}
I SUGGEST YOU ADD OPTIONAL PARAMETER ON YOUR METHOD TO DECIDE WHICH UPDATE TO USE
It depends on what your priorities are on the project:
using your already existing update method is gonna update everything all the time, incressing traffic, IO and process time (validation and so on...)
If you're on a project where properties are timestamped, they would be updated even if the value hasn't really changed...
If you don't mind about all this, use your update() method all the time.
My personnal POV is: create a new method (with an explicit name). This will same process time from now on and thinking time in 2 years when you'll have to change this class ;)
I don't know if this is what you should do necessarily, but here's something you could do: Create a SetAll or SetMany or whatever method where you pass in another instance of your class (source). Check each property and if it's non-null, you set the destination object's property value to the source object's property value. Note that this tactic will depend on nullable types, and assumes you can ignore null values passed into a new setter method. Here's an illustration:
using System;
namespace BlogPartialUpdateTrick
{
public class SomeClass
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int? HeightInches { get; set; }
public DateTime? Dob { get; set; }
public void SetAll(SomeClass source)
{
this.FirstName = source.FirstName ?? this.FirstName;
this.LastName = source.LastName ?? this.LastName;
this.HeightInches = source.HeightInches ?? this.HeightInches;
this.Dob = source.Dob ?? this.Dob;
}
public override string ToString()
{
return String.Format("fn: {0}, ln: {1}, height: {2}, DOB: {3}", FirstName ?? String.Empty, LastName ?? String.Empty,
HeightInches.HasValue ? HeightInches.Value.ToString() : "null", Dob.HasValue ? Dob.Value.ToShortDateString() : "null" );
}
}
}
In this first code sample, We have my spiffy class SomeClass. It's got 4 properties, all of which are nullable. The noteworthy part of this class is the SetAllMethod where I can pass in a source object which is also of type SomeClass. It sets this instance's property values to the values passed in the source parameter, but only if they're non-null. Here's a 2nd code blurb where I'm using this stuff:
using System;
using System.Windows.Forms;
namespace BlogPartialUpdateTrick
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var destination = new SomeClass() { FirstName = "Freddy", LastName = "Fingers", Dob = DateTime.Parse("01/01/1970"), HeightInches = 72 };
var source = new SomeClass() { FirstName = null, LastName="Flippers", Dob = null, HeightInches = 80 };
destination.SetAll(source);
MessageBox.Show(destination.ToString());
}
}
}
Create a destination object, a source object, call the new method, voila! output is this:
"fn: Freddy, ln: Flippers, height: 80, DOB: 1/1/1970"
You should probably use Entity Framework and let the context do it for you. Using EF, you'll be able to update Entities like this :
try
{
var original = ObjectContext.Set<Request>().SingleOrDefault(x => x.Id.Equals(_request.Id));
if (original != null)
{
ObjectContext.Entry(original).CurrentValues.SetValues(_request);
}
return ObjectContext.SaveChanges();
}
catch (Exception ee)
{
return -1;
}

Using JsonConvert.DeserializeObject to deserialize Json to a C# POCO class

Here is my simple User POCO class:
/// <summary>
/// The User class represents a Coderwall User.
/// </summary>
public class User
{
/// <summary>
/// A User's username. eg: "sergiotapia, mrkibbles, matumbo"
/// </summary>
public string Username { get; set; }
/// <summary>
/// A User's name. eg: "Sergio Tapia, John Cosack, Lucy McMillan"
/// </summary>
public string Name { get; set; }
/// <summary>
/// A User's location. eh: "Bolivia, USA, France, Italy"
/// </summary>
public string Location { get; set; }
public int Endorsements { get; set; } //Todo.
public string Team { get; set; } //Todo.
/// <summary>
/// A collection of the User's linked accounts.
/// </summary>
public List<Account> Accounts { get; set; }
/// <summary>
/// A collection of the User's awarded badges.
/// </summary>
public List<Badge> Badges { get; set; }
}
And the method I'm using to deserialize a JSON response into a User object (this actual JSON call is here):
private User LoadUserFromJson(string response)
{
var outObject = JsonConvert.DeserializeObject<User>(response);
return outObject;
}
This fires an exception:
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type
'System.Collections.Generic.List`1[CoderwallDotNet.Api.Models.Account]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly.
To fix this error either change the JSON to a JSON array
(e.g. [1,2,3]) or change the deserialized type so that it is a normal
.NET type (e.g. not a primitive type like integer, not a collection
type like an array or List) that can be deserialized from a JSON
object. JsonObjectAttribute can also be added to the type to force it
to deserialize from a JSON object. Path 'accounts.github', line 1,
position 129.
Having never worked with this DeserializeObject method before, I'm kind of stuck here.
I've made sure that the property names in the POCO class are the same as the names in the JSON response.
What can I try to deserialize JSON into this POCO class?
Here is a working example.
Keypoints are:
Declaration of Accounts
Use of JsonProperty attribute
.
using (WebClient wc = new WebClient())
{
var json = wc.DownloadString("http://coderwall.com/mdeiters.json");
var user = JsonConvert.DeserializeObject<User>(json);
}
-
public class User
{
/// <summary>
/// A User's username. eg: "sergiotapia, mrkibbles, matumbo"
/// </summary>
[JsonProperty("username")]
public string Username { get; set; }
/// <summary>
/// A User's name. eg: "Sergio Tapia, John Cosack, Lucy McMillan"
/// </summary>
[JsonProperty("name")]
public string Name { get; set; }
/// <summary>
/// A User's location. eh: "Bolivia, USA, France, Italy"
/// </summary>
[JsonProperty("location")]
public string Location { get; set; }
[JsonProperty("endorsements")]
public int Endorsements { get; set; } //Todo.
[JsonProperty("team")]
public string Team { get; set; } //Todo.
/// <summary>
/// A collection of the User's linked accounts.
/// </summary>
[JsonProperty("accounts")]
public Account Accounts { get; set; }
/// <summary>
/// A collection of the User's awarded badges.
/// </summary>
[JsonProperty("badges")]
public List<Badge> Badges { get; set; }
}
public class Account
{
public string github;
}
public class Badge
{
[JsonProperty("name")]
public string Name;
[JsonProperty("description")]
public string Description;
[JsonProperty("created")]
public string Created;
[JsonProperty("badge")]
public string BadgeUrl;
}
Another, and more streamlined, approach to deserializing a camel-cased JSON string to a pascal-cased POCO object is to use the CamelCasePropertyNamesContractResolver.
It's part of the Newtonsoft.Json.Serialization namespace. This approach assumes that the only difference between the JSON object and the POCO lies in the casing of the property names. If the property names are spelled differently, then you'll need to resort to using JsonProperty attributes to map property names.
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
. . .
private User LoadUserFromJson(string response)
{
JsonSerializerSettings serSettings = new JsonSerializerSettings();
serSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
User outObject = JsonConvert.DeserializeObject<User>(jsonValue, serSettings);
return outObject;
}
The accounts property is defined like this:
"accounts":{"github":"sergiotapia"}
Your POCO states this:
public List<Account> Accounts { get; set; }
Try using this Json:
"accounts":[{"github":"sergiotapia"}]
An array of items (which is going to be mapped to the list) is always enclosed in square brackets.
Edit: The Account Poco will be something like this:
class Account {
public string github { get; set; }
}
and maybe other properties.
Edit 2: To not have an array use the property as follows:
public Account Accounts { get; set; }
with something like the sample class I've posted in the first edit.
You could create a JsonConverter. See here for an example thats similar to your question.
Along the lines of the accepted answer, if you have a JSON text sample you can plug it in to this converter, select your options and generate the C# code.
If you don't know the type at runtime, this topic looks like it would fit.
dynamically deserialize json into any object passed in. c#
to fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the
deserialized type so that it is a normal .NET type (e.g. not a primitive type like
integer, not a collection type like an array or List) that can be deserialized from a
JSON object.`
The whole message indicates that it is possible to serialize to a List object, but the input must be a JSON list.
This means that your JSON must contain
"accounts" : [{<AccountObjectData}, {<AccountObjectData>}...],
Where AccountObject data is JSON representing your Account object or your Badge object
What it seems to be getting currently is
"accounts":{"github":"sergiotapia"}
Where accounts is a JSON object (denoted by curly braces), not an array of JSON objects (arrays are denoted by brackets), which is what you want. Try
"accounts" : [{"github":"sergiotapia"}]
That's not exactly what I had in mind. What do you do if you have a generic type to only be known at runtime?
public MyDTO toObject() {
try {
var methodInfo = MethodBase.GetCurrentMethod();
if (methodInfo.DeclaringType != null) {
var fullName = methodInfo.DeclaringType.FullName + "." + this.dtoName;
Type type = Type.GetType(fullName);
if (type != null) {
var obj = JsonConvert.DeserializeObject(payload);
//var obj = JsonConvert.DeserializeObject<type.MemberType.GetType()>(payload); // <--- type ?????
...
}
}
// Example for java.. Convert this to C#
return JSONUtil.fromJSON(payload, Class.forName(dtoName, false, getClass().getClassLoader()));
} catch (Exception ex) {
throw new ReflectInsightException(MethodBase.GetCurrentMethod().Name, ex);
}
}
May be late but using QuickType is the easiest way to do that:
https://app.quicktype.io/
For anyone having this problem i was not seeing the json value properly. https://jsonutils.com/ there you can check the classes that should be generated and return ONLY ONE of those classes once you read the json in your code.
For example i needed a booklist object so my code should only read one
res = await response.Content.ReadAsAsync<BookList>();
Where booklist looks something like
public class BookList
{
[JsonProperty("data")]
public IList<Datum> Data { get; set; }
}
And in that list have smaller book clasess that the converter named Datum (just books)
public class Datum
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("isbn")]
public string Isbn { get; set; }
}
Again, if you have doubts https://jsonutils.com/

Categories