I have pasted JSON in to my C# console application, so it produces classes like so :
public class Rootobject
{
public Id id { get; set; }
}
public class Id
{
public Identifier Identifier { get; set; }
}
public class Identifier
{
public Id1 id { get; set; }
public Type type { get; set; }
}
public class Id1
{
public string IdentifierString { get; set; }
}
public class Type
{
public string IdentifierType { get; set; }
}
I wish to set the values of identifierString and identifierType like so :
var node = new Rootobject();
node.id.Identifier.id.IdentifierString = "testId";
node.id.Identifier.type.IdentifierType = "idType";
However, I get an 'Object reference not set to an instance of an object' error.
you should write:
var node = new Rootobject();
node.id = new Id();
node.id.Identifier = new Identifier();
node.id.Identifier.id = new Id1();
node.id.Identifier.type = new Type();
node.id.Identifier.id.IdentifierString = "testId";
node.id.Identifier.type.IdentifierType = "idType";
or even better:
var node = new Rootobject
{
id = new Id
{
Identifier = new Identifier
{
id = new Id1 { IdentifierString = "id" },
type = new Type { IdentifierType = "type" },
}
}
};
You are missing creation of objects, they are nulls
Or version which compile :)
var node = new RootObject
{
id = new Id
{
Identifier = new Identifier
{
id = new Id1 { IdentifierString = "id" },
type = new Type { IdentifierType = "type" },
}
}
};
Related
I want to get the property name and the value from object and pass them to the list.
i dont want to pass one by one property and value to the list like commented in my code. want to use loop and add name and value dynamically
public class ParametersList
{
public string Name { get; set; }
public dynamic Value { get; set; }
}
public class BookVM
{
public string AuthorName{ get; set; }
public string CoverUrl { get; set; }
public int AuthorIds { get; set; }
}
public List<Book> Addgetallbooks(BookVM BookVM)
{
List<ParametersList> obj = new List<ParametersList>();
//List<ParametersList> obj = new List<ParametersList>
//{
// new ParametersList{Name=nameof(BookVM.AuthorIds),Value=BookVM.AuthorIds},
// new ParametersList{Name=nameof(BookVM.AuthorName),Value=BookVM.AuthorName},
// new ParametersList{Name=nameof(BookVM.CoverUrl),Value=BookVM.CoverUrl}
//};
var getdata = _opr.GetBooks1(obj);
return getdata;
}
You need to use reflection, but not sure if you should do it :)
[TestMethod]
public void Foo()
{
var book = new BookVM() { AuthorIds = 1, AuthorName = "some name", CoverUrl = "some cover url" };
var result = GetParameters(book);
result.Should().BeEquivalentTo(new[]
{
new ParametersList { Name = nameof(BookVM.AuthorIds), Value = 1 },
new ParametersList() { Name = nameof(BookVM.AuthorName), Value = "some name" },
new ParametersList { Name = nameof(BookVM.CoverUrl), Value = "some cover url" }
});
}
private static List<ParametersList> GetParameters(BookVM book)
{
return typeof(BookVM).GetProperties().Select(p => new ParametersList
{
Name = p.Name, Value = p.GetValue(book)
}).ToList();
}
Is there any scope for improvement in my program which converts flat db entity to a tree data structure.
I don't want to loose the Generic flexibility as i should be able to use the same method for any other DBEntity class
Interface for db entity class
public interface IDbEntityNode
{
int Id { get; set; }
int ParentId { get; set; }
}
Example of db Entity class
public class ExceptionCategory :IDbEntityNode
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Data { get; set; }
public ExceptionCategory(string data, int id, int parentId)
{
Id = id;
ParentId = parentId;
Data = data;
}
}
Generic class which holds the structure of tree node
public class GenericNode<T>
{
public T NodeInformation { get; set; }
public GenericNode<T> Parent { get; set; }
public List<GenericNode<T>> Children { get; set; } = new List<GenericNode<T>>();
}
Method which coverts flat list to tree
public static List<GenericNode<T>> CreateGenericTree<T>(List<T> flatDataObject,Func<T,bool> IsRootNode) where T : IDbEntityNode
{
var lookup = new Dictionary<int, GenericNode<T>>();
var rootNodes = new List<GenericNode<T>>();
var noOfElements = flatDataObject.Count;
for (int element = 0; element < noOfElements; element++)
{
GenericNode<T> currentNode;
if (lookup.TryGetValue(flatDataObject[element].Id, out currentNode))
{
currentNode.NodeInformation = flatDataObject[element];
}
else
{
currentNode = new GenericNode<T>() { NodeInformation = flatDataObject[element] };
lookup.Add(flatDataObject[element].Id, currentNode);
}
if (IsRootNode(flatDataObject[element]))
{
rootNodes.Add(currentNode);
}
else
{
GenericNode<T> parentNode;
if (!lookup.TryGetValue(flatDataObject[element].ParentId, out parentNode))
{
parentNode = new GenericNode<T>();
lookup.Add(flatDataObject[element].ParentId, parentNode);
}
parentNode.Children.Add(currentNode);
currentNode.Parent = parentNode;
}
}
return rootNodes;
}
Execution:
private static void Main(string[] args)
{
List<IDbEntityNode> flatDataStructure = new List<IDbEntityNode>
{
new ExceptionCategory("System Exception",1,0),
new ExceptionCategory("Index out of range",2,1),
new ExceptionCategory("Null Reference",3,1),
new ExceptionCategory("Invalid Cast",4,1),
new ExceptionCategory("OOM",5,1),
new ExceptionCategory("Argument Exception",6,1),
new ExceptionCategory("Argument Out Of Range",7,6),
new ExceptionCategory("Argument Null",8,6),
new ExceptionCategory("External Exception",9,1),
new ExceptionCategory("Com",10,9),
new ExceptionCategory("SEH",11,9),
new ExceptionCategory("Arithmatic Exception",12,1),
new ExceptionCategory("DivideBy0",13,12),
new ExceptionCategory("Overflow",14,12),
};
var tree = CreateGenericTree(flatDataStructure, IsRootNode);
}
private static bool IsRootNode(IDbEntityNode dbEntity)
{
bool isRootNode = false;
if (dbEntity.ParentId == 0 )
isRootNode = true;
return isRootNode;
}
Created a generic approach, table objects need to follow the dbSet interface and TreeNode objects need to follow the ITreeNode. I used binarySerach to make this as fast as possible. No recursion needed. The logic ensures that you do not need to have the items in a particular order. I did not throw an error when out of the loop when there are still unassigned objects, this can be easy added.
using System.Collections.Generic;
public interface ITreeNode
{
string ParentId { get; set; }
string Id { get; set; }
dbItem item { get; set; }
List<ITreeNode> Nodes { get; set; }
}
public class TreeNode : ITreeNode
{
public TreeNode()
{ }
public string ParentId { get; set; }
public string Id { get; set; }
public dbItem item { get; set; }
public List<ITreeNode> Nodes { get; set; }
}
public class dbItem
{
public string ParentId { get; set; }
public string Id { get; set; }
public string Name { get; set; }
}
class app
{
static void Main()
{
List<dbItem> dbSet = new List<dbItem>();
dbSet.Add(new dbItem() { Id = "5", ParentId = "1", Name = "Jan" });
dbSet.Add(new dbItem() { Id = "25", ParentId = "1", Name = "Maria" });
dbSet.Add(new dbItem() { Id = "1", Name = "John" });
dbSet.Add(new dbItem() { Id = "8", ParentId = "2", Name = "Cornelis" });
dbSet.Add(new dbItem() { Id = "2", Name = "Ilse" });
dbSet.Add(new dbItem() { Id = "3", Name = "Nick" });
dbSet.Add(new dbItem() { Id = "87", ParentId = "5", Name = "Rianne" });
dbSet.Add(new dbItem() { Id = "67", ParentId = "3000", Name = "Rianne" });
dbSet.Add(new dbItem() { Id = "3000", Name = "Max" });
List<TreeNode> result = BuildTree<TreeNode>(dbSet);
}
private class ParentComparer<T> : IComparer<ITreeNode> where T: ITreeNode
{
public int Compare(ITreeNode x, ITreeNode y)
{
if (x.ParentId == null) return -1; //have the parents first
return x.ParentId.CompareTo(y.ParentId);
}
}
private class IdComparer<T> : IComparer<ITreeNode> where T : ITreeNode
{
public int Compare(ITreeNode x, ITreeNode y)
{
return x.Id.CompareTo(y.Id);
}
}
static private List<T> BuildTree<T> (List<dbItem> table) where T: ITreeNode, new()
{
//temporary list of tree nodes to build the tree
List<T> tmpNotAssignedNodes = new List<T>();
List<T> tmpIdNodes = new List<T>();
List<T> roots = new List<T>();
IComparer<T> pc = (IComparer<T>) new ParentComparer<T>();
IComparer<T> ic = (IComparer<T>) new IdComparer<T>();
foreach (dbItem item in table)
{
T newNode = new T() { Id = item.Id, ParentId = item.ParentId, item = item };
newNode.Nodes = new List<ITreeNode>();
T dummySearchNode = new T() { Id = item.ParentId, ParentId = item.ParentId };
if (string.IsNullOrEmpty(item.ParentId))
roots.Add(newNode);
else
{
int parentIndex = tmpIdNodes.BinarySearch(dummySearchNode, ic);//Get the parent
if (parentIndex >=0)
{
T parent = tmpIdNodes[parentIndex];
parent.Nodes.Add(newNode);
}
else
{
parentIndex = tmpNotAssignedNodes.BinarySearch(dummySearchNode, pc);
if (parentIndex < 0) parentIndex = ~parentIndex;
tmpNotAssignedNodes.Insert(parentIndex, newNode);
}
}
dummySearchNode.ParentId = newNode.Id;
//Cleanup Unassigned
int unAssignedChildIndex = tmpNotAssignedNodes.BinarySearch(dummySearchNode, pc);
while (unAssignedChildIndex >= 0 && unAssignedChildIndex < tmpNotAssignedNodes.Count)
{
if (dummySearchNode.ParentId == tmpNotAssignedNodes[unAssignedChildIndex].ParentId)
{
T child = tmpNotAssignedNodes[unAssignedChildIndex];
newNode.Nodes.Add(child);
tmpNotAssignedNodes.RemoveAt(unAssignedChildIndex);
}
else unAssignedChildIndex--;
}
int index = tmpIdNodes.BinarySearch(newNode, ic);
tmpIdNodes.Insert(~index, newNode);
}
return roots;
}
}
Try following solution using recursive code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
public static List<IDbEntityNode> flatDataStructure = null;
public static Dictionary<int?, List<IDbEntityNode>> dict = null;
static void Main(string[] args)
{
flatDataStructure = new List<IDbEntityNode>
{
new ExceptionCategory("System Exception",1,0),
new ExceptionCategory("Index out of range",2,1),
new ExceptionCategory("Null Reference",3,1),
new ExceptionCategory("Invalid Cast",4,1),
new ExceptionCategory("OOM",5,1),
new ExceptionCategory("Argument Exception",6,1),
new ExceptionCategory("Argument Out Of Range",7,6),
new ExceptionCategory("Argument Null",8,6),
new ExceptionCategory("External Exception",9,1),
new ExceptionCategory("Com",10,9),
new ExceptionCategory("SEH",11,9),
new ExceptionCategory("Arithmatic Exception",12,1),
new ExceptionCategory("DivideBy0",13,12),
new ExceptionCategory("Overflow",14,12),
};
dict = flatDataStructure.GroupBy(x => x.ParentId, y => y)
.ToDictionary(x => x.Key, y => y.ToList());
GenericNode<IDbEntityNode> root = new GenericNode<IDbEntityNode>();
root.Parent = null;
int rootId = 0;
root.NodeInformation.Id = rootId;
root.NodeInformation.name = "root";
root.NodeInformation.ParentId = null;
CreateGenericTree(root);
}
public static void CreateGenericTree<T>(GenericNode<T> parent) where T : IDbEntityNode, new()
{
if (dict.ContainsKey(parent.NodeInformation.Id))
{
List<IDbEntityNode> children = dict[parent.NodeInformation.Id];
foreach (IDbEntityNode child in children)
{
GenericNode<T> newChild = new GenericNode<T>();
if (parent.Children == null) parent.Children = new List<GenericNode<T>>();
parent.Children.Add(newChild);
newChild.NodeInformation.Id = child.Id;
newChild.NodeInformation.ParentId = parent.NodeInformation.Id;
newChild.NodeInformation.name = child.name;
newChild.Parent = parent;
CreateGenericTree(newChild);
}
}
}
}
public class GenericNode<T> where T : new()
{
public T NodeInformation = new T();
public GenericNode<T> Parent { get; set; }
public List<GenericNode<T>> Children { get; set; }
}
public class IDbEntityNode
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string name { get; set; }
}
public class ExceptionCategory : IDbEntityNode
{
public string Data { get; set; }
public ExceptionCategory(string data, int id, int parentId)
{
Id = id;
ParentId = parentId;
Data = data;
}
}
}
I have a MongoDB collection that has documents that look like the following:
{
"Name" : "Name1",
"AA" : [
{
"B" : {
"Name" : "Name2"
},
"CC" : [
{
"Field" : "Value"
}
]
}
]
}
I am working from C# with the 2.7 MongoDB driver.
I want to push an element to the CC array of those elements of AA that match a certain condition. I was able to do that with following code:
[TestFixture]
class TestClass
{
[Test]
public void Test()
{
var b = new B { Name = "Name2" };
var c = new C { Field = "Value2" };
var field = new StringFieldDefinition<Document>("AA.$[element].CC");
var updateDefinition = Builders<Document>
.Update
.Push(field, c);
var arrayFilterBson = new BsonDocument("element.B",
new BsonDocument("$eq", b.ToBsonDocument()));
var arrayFilter = new BsonDocumentArrayFilterDefinition<AgentRecord>(arrayFilterBson);
var documentFilter = Builders<Document>.Filter.Eq(r => r.Name, "Name1");
var updateOptions = new UpdateOptions
{
IsUpsert = false,
ArrayFilters = new ArrayFilterDefinition[] { arrayFilter }
};
var settings = new MongoClientSettings
{
Server = new MongoServerAddress("localhost", 27000)
};
var mongoClient = new MongoClient(settings);
var database = mongoClient.GetDatabase("so-question");
var collection = database.GetCollection<Document>("collection");
collection.UpdateOne(documentFilter, updateDefinition, updateOptions);
}
}
// Mapping classes
public class Document
{
public string Name { get; set; }
public A[] AA { get; set; }
}
public class A
{
public B B { get; set; }
public C[] CC { get; set; }
}
public class B
{
public string Name { get; set; }
}
public class C
{
public string Field { get; set; }
}
Is there a way to achieve the same through the typed API to avoid having to hardcode the name of the fields in definitions such as AA.$[element].CC or element.B?
I am of course worried about having to change these hard-coded expressions when the name of the properties of the classes change or for example if I make use of the [BsonElement("name")] attribute to control the name of the mapped property.
How can I add the following data on the table into a list called Vehicles?
public class criterias
{
public double values { get; set; }
public double time { get; set; }
}
public class movChannels
{
public string name { get; set; }
public IList<criterias> criteria = new List<criterias>();
}
public class stepsList
{
public string steps { get; set; }
public IList<movChannels> stepChannelsCriteria = new List<movChannels>();
}
public class vehicles
{
public int vehID { get; set; }
public string vehDescription { get; set; }
public IList<stepsList> vehValCriteria = new List<stepsList>();
}
Now, how can I add the data that I have in the table shown into a list called Vehicles? I will create other vehicles later...
You had several bad decisions, some were design flaws and some were minor C# naming convention violations.
Couple of worth mentions flaws:
vehID should have been a string and not int (Example "XPT")
Movment has Name, Value and Time. It doesn't have a list of Values and Times.
Creation:
List<Vehicle> vehicles = new List<Vehicle>();
Vehicle vehicle = new Vehicle()
{
Id = "XPT",
Description = "Average Car",
Steps = new List<Step>()
{
new Step() {
Name = "move car",
Movements = new List<Movement>()
{
new Movement("engage 1st gear", 1, 1),
new Movement("reach 10kph", 10, 5),
new Movement("maintain 10kph", 10, 12),
}
},
new Step() {
Name = "stop car",
Movements = new List<Movement>()
{
new Movement("reach 0kph", 10, 4),
new Movement("put in neutral", 0, 1),
new Movement("turn off vehicle", 0, 0),
}
}
}
};
vehicles.Add(vehicle);
Entities:
public class Movement
{
public string Name { get; set; }
public double Values { get; private set; }
public double Time { get; private set; }
public Movement(string name, double values, double time)
{
Name = name;
Values = values;
Time = time;
}
}
public class Step
{
public string Name { get; set; }
public IList<Movement> Movements { get; set; }
}
public class Vehicle
{
public string Id { get; set; } // Should be changed to string
public string Description { get; set; }
public IList<Step> Steps { get; set; }
}
You should create your classes like the following:
public class criterias
{
public double values { get; set; }
public double time { get; set; }
}
public class movChannels
{
public movChannels
{
criteria = new List<criterias>();
}
public string name { get; set; }
public IList<criterias> criteria { get; set; }
}
public class stepsList
{
public stepsList
{
stepChannelsCriteria = new List<movChannels>();
}
public string steps { get; set; }
public IList<movChannels> stepChannelsCriteria { get; set; }
}
public class vehicles
{
public vehicles
{
vehValCriteria = new List<stepsList>();
}
public int vehID { get; set; }
public string vehDescription { get; set; }
public IList<stepsList> vehValCriteria { get; set; }
public movChannels movments { get; set; }
}
What about that?
public class VehiclesViewModel
{
public List<vehicles> Vehicles { get; private set; }
public void Initalize()
{
this.Vehicles = new List<vehicles>();
var vehicle = new vehicles
{
vehID = 1,
vehDescription = "firstDescription",
};
var stepsList = new stepsList
{
steps = "firstStep",
};
var movChannel = new movChannels
{
name = "firstChannel",
};
var criteria = new criterias
{
values = 0.5,
time = 0.5
};
movChannel.criteria.Add(criteria);
stepsList.stepChannelsCriteria.Add(movChannel);
vehicle.vehValCriteria.Add(stepsList);
this.Vehicles.Add(vehicle);
}
}
it seems in your table the VehicleId is of type string. Make sure your VehicleId property in Vehicle class also matches the same.
You can use the collection initializers to set the values of child objects like this way:
var data = new vehicles()
{
vehID = 1,
vehDescription = "Average Car",
vehValCriteria = new List<stepsList>()
{
new stepsList()
{
steps = "Move car",
stepChannelsCriteria = new List<movChannels>()
{
new movChannels()
{
name = "engage firstgear",
criteria = new List<criterias>()
{
new criterias()
{
values = 1,
time = 1
},
}
},
new movChannels()
{
name = "reach 10kph",
criteria = new List<criterias>()
{
new criterias()
{
values = 10,
time = 5
},
}
},
new movChannels()
{
name = "maintain 10kph",
criteria = new List<criterias>()
{
new criterias()
{
values = 10,
time = 12
},
}
}
}
},
new stepsList()
{
steps = "stop car",
stepChannelsCriteria = new List<movChannels>()
{
new movChannels()
{
name = "reach okph",
criteria = new List<criterias>()
{
new criterias()
{
values = 10,
time = 4
},
}
},
new movChannels()
{
name = "put in neutral",
criteria = new List<criterias>()
{
new criterias()
{
values = 0,
time = 1
},
}
},
new movChannels()
{
name = "turn off vehicle",
criteria = new List<criterias>()
{
new criterias()
{
values = 0,
time = 0
},
}
}
}
}
}
};
You can fill your list by moving from top to bottom, like
Create Criterias List then Create movChannel object and add that list
to Criterias object and so on
However if you want to avoid this way, there is another way. If you are using Linq To List then follow this
Get a simple flat object to a list object
var TableData = db.Tablename.Tolist();
Then fill your own object like this
Vehicles finalList = TableData.Select(a => new Vehicles()
{
vehID = a.Id,
vehDescription = a.des,
vehValCriteria = TableData.Where(b => b.StepslistId == a.StepslistId)
.Select(c => new StepsList()
{
steps = c.Steps,
stepChannelsCriteria = TableData.Where(d => d.channelId == c.channelId)
.select(e => new MovChannels()
{
name = e.name,
criteria = TableData.Where(f => f.criteriasId = e.criteriasId)
.Select(g => new Criterias()
{
values = g.Values,
time = g.Time
}).ToList()
}).ToList()
}).ToList()
}).ToList();
This is standard way to fill list within list
I'm working with KnockoutMVC and it requires strongly type models to use inside the VIEW. I have tried multiple variations of the examples on KnockoutMVC's site including using ENUMS and still could not get it to work. Perhaps this is a problem with the setup of my models.
MODELS
public class PhoneNumber
{
public List<NumberTypeClass> Types { get; set; }
//public NumberType enumType { get; set; }
//public enum NumberType
//{
// Work,
// Home,
// Mobile,
// Fax
//}
private string _number;
[StringLength(14, MinimumLength = 10, ErrorMessage = "Please use (123) 456-7890 format"), Required]
public string Number
{
get
{
this._number = BeautifyPhoneNumber(this._number);
return this._number;
}
set
{
this._number = value;
}
}
public string Extension { get; set; }
public static String BeautifyPhoneNumber(string numberToBeautify)
{
//beautifyNumberCode
}
}
public class NumberTypeClass
{
public int Id { get; set; }
public string NumberType { get; set; }
}
public class VendorsEditorVendorModel
{
public string FirstName {Get;set;}
public string LastName {get;set;}
public List<Address> Address {get;set;}
public List<PhoneNumber> Phones {get;set;}
}
public class VendorsEditorModel
{
public List<VendorsEditorVendorModel> Vendors {get;set;}
}
CONTROLLER
public class VendorsEditorController : BaseController
{
public ActionResult CreateVendors()
{// VendorsEditor/CreateVendors
var vendor = new VendorsEditorModel();
vendor.Vendors = new List<VendorsEditorVendorModel>();
vendor.Vendors[0].Phones[0].Types = new List<NumberTypeClass>
{
new NumberTypeClass{Id = 0, TypeName = "Mobile"},
new NumberTypeClass{Id = 0, TypeName = "Work"},
new NumberTypeClass{Id = 0, TypeName = "Home"}
};//this throws an error because there is no Vendors[0] ...but how would i populate this list for every Vendor?
return View(vendor);
}
}
You cannot call an empty collection by index [x]. You need to fill your collection from a database or what not before you can access items in it. If you are just trying to add items to a collection, this is how you do it:
var vendor = new VendorsEditorModel
{
Vendors = new List<VendorsEditorVendorModel>
{
new VendorsEditorVendorModel
{
Phones = new List<PhoneNumber>
{
new PhoneNumber
{
Types = new List<NumberTypeClass>
{
new NumberTypeClass {Id = 0, NumberType = "Mobile"}
}
}
}
}
}
};
If you just want to add the types to an already populated collection, you can do the following:
foreach (var phone in vendor.Vendors.SelectMany(item => item.Phones))
{
phone.Types = new List<NumberTypeClass>
{
new NumberTypeClass{Id = 0, NumberType = "Mobile"},
new NumberTypeClass{Id = 0, NumberType = "Work"},
new NumberTypeClass{Id = 0, NumberType = "Home"}
};
}