Represent string data to tree - c#

I have the following data. This is a list of programs on my system.
[
{
"ID": 135,
"CODIGO": 139,
"NOME": "CADASTRO DE ANOS ATIVOS",
"VISAO": "VANOSATIVOSCONTABIL",
"CAMINHO": "Cadastros/Contabilidade/frm_AnosAtivosContabil.aspx, 139, ((VariaveisSistema)Session[VariaveisSistema]).UsuarioId.ToString().Trim(), frm_Visoes.aspx, , Nao"
},
{
"ID": 59,
"CODIGO": 35,
"NOME": "CADASTRO DE CENTRO DE CUSTO",
"VISAO": "VCENTROCUSTO",
"CAMINHO": "Cadastros/Contabilidade/frm_CadastroCentroCusto.aspx, 035, ((VariaveisSistema)Session[VariaveisSistema]).UsuarioId.ToString().Trim(), frm_Visoes.aspx, , Nao"
},
]
So, you can see that the program has a path like Cadastros/Contabilidade.
I need to conver the Cadastros/Contabilidade in a menu tree colapsable.
So the json data should look like this:
Cadastros
|
| Contabilidade
- frm_AnosAtivosContabil.aspx
- frm_CadastroCentroCusto.aspx
- frm_CadastroCFOP.aspx
- ...
| Globais
- frm_AlteraFormacaoArvore.aspx
- frm_AssociacaoCalendario.aspx
- frm_AssociacaoItemTransferencia.aspx
- ...
I am using C#. I managed to separate the programs along the way (group them). But I have not managed to separate them into menus.
The node structure is:
public class Node
{
public IList<Programa> Programs { get; set; }
public string Name { get; set; }
public string FullName { get; set; }
public Node Parent { get; set; }
public IList<Node> Childrens { get; set; }
}
Program structure:
public class Programa
{
public int Id { get; set; }
public int Codigo { get; set; }
public string Nome { get; set; }
public string Visao { get; set; }
public IList<UsuarioPrograma> UsuariosPrograma { get; set; }
public string Caminho { get; set; }
}
I can create the root node. But i dont kno how to proceed.
private void CreateNode(Programa programa)
{
var paths = programa.Caminho.Split('/');
// Verifica se já é o pai
if (paths.Length == 1)
{
// Verifica se o nó já existe
var node = Menu.FirstOrDefault(x => x.Name == paths[0]);
if (node == null)
{
node = new Node();
node.Name = paths[0];
node.Programs = new List<Programa> { programa };
Menu.Add(node);
}
else Menu.First(x => x.Name == paths[0]).Programs.Add(programa);
}
}

#augusto-henrique bit tricky but managed to bring the json object however you expecting to serialize, have a look this code and see whether this works for your requirements,
first I created a class to serialize the JSON you have
public class Page
{
public int ID { get; set; }
public int CODIGO { get; set; }
public string NOME { get; set; }
public string VISAO { get; set; }
public string CAMINHO { get; set; }
}
Then I am grouping the values and adding into dictionary objects as nested collection
var json1 = JsonConvert.DeserializeObject<List<Page>>
(File.ReadAllText(#"c:\temp\test1.json"));
var root1 = json1.Select(x => x.CAMINHO)
.Select(x => x.Split(",")[0])
.Select(x => x.Split("/"))
.Select(x => new
{
level1 = x.First(),
level2 = x.Skip(1).First(),
level3 = x.Skip(2).First()
})
.GroupBy(x => new { x.level1, x.level2, x.level3 }, (key, grp) => new
{
Level1 = key.level1,
Level2 = key.level2,
Level3 = key.level3,
groups = grp
});
var jsonObject = new Dictionary<string, object>();
foreach (var level1 in root1)
{
if (!jsonObject.ContainsKey(level1.Level1))
{
jsonObject.Add(level1.Level1, new Dictionary<string, object[]>());
}
if (!((Dictionary<string, object[]>)jsonObject[level1.Level1]).ContainsKey(level1.Level2))
((Dictionary<string, object[]>)jsonObject[level1.Level1]).Add(level1.Level2, new[] { level1.Level3 });
else
{
var list = (((Dictionary<string, object[]>)jsonObject[level1.Level1])[level1.Level2]).ToList();
list.Add(level1.Level3);
((Dictionary<string, object[]>)jsonObject[level1.Level1])[level1.Level2] = list.ToArray();
}
}
var jsonText = JsonConvert.SerializeObject(jsonObject);
the result of jsonText would look like, hope from this you can develop further., may require some refactoring,

Related

Filter data from 2 lists with diferent models C#

I have this models
public class RoutingAttributeModel
{
public int Bus_No { get; set; }
public int Attribute_No { get; set; }
public string Attribute_Name { get; set; }
public string Status { get; set; }
public string Notes { get; set; }
}
public class AgentRoutingAttributeModel
{
public int Agent_No { get; set; }
public int Bus_No { get; set; }
public int Attribute_No { get; set; }
public string Attribute_Name { get; set; }
public string Status { get; set; }
}
List<RoutingAttributeModel> lstComplete = new List<RoutingAttributeModel>();
List<AgentRoutingAttributeModel> lstAssigned = new List<AgentRoutingAttributeModel>();
Filled this with some data
Is it possible to filter with Linq? I want to save in a new list the diferent content between lstComplete and lstAssigned
I was trying to join both lists but got stuck there
var results1 = from cl in lstComplete
join al in lstAssigned
on cl.Attribute_No equals al.Attribute_No
select cl;
you can use linq
as my understanding, you try to find linked by attribute_No records and have a list of not matching properties?
lstComplete.Add(new RoutingAttributeModel(){
Attribute_Name = "aaa",
Attribute_No = 1,
Bus_No = 1,
Notes = "",
Status = "status"
});
lstAssigned.Add(new AgentRoutingAttributeModel()
{
Attribute_No = 1,
Agent_No = 10,
Bus_No = 1,
Attribute_Name = "bbb",
Status = "status2"
});
var lst = lstComplete
.Join(lstAssigned,
complete => complete.Attribute_No,
assigned => assigned.Attribute_No,
(complete, assigned) => new { lstComplete = complete, lstAssigned = assigned })
.Select(s => new { s.lstComplete, s.lstAssigned})
.Where(w=>
w.lstAssigned.Attribute_Name != w.lstComplete.Attribute_Name
|| w.lstAssigned.Bus_No != w.lstComplete.Bus_No
)
.ToList()
.Dump();
so result would be
You could try the following query
var filteredList = lstComplete
.Where(x => !lstAssigned.Any(y => y.Attribute_No == x.Attribute_No));

Returning a List<> inheritance C#

class cuentaBancaria
{
public cuentaBancaria()
{
}
public cuentaBancaria(string nombreCliente, string numCuenta, double tipoInteres, double saldo)
{
this.nombreCliente = nombreCliente;
this.numCuenta = numCuenta;
this.tipoInteres = tipoInteres;
this.saldo = saldo;
}
public string nombreCliente { get; set; }
public string numCuenta { get; set; }
public double tipoInteres { get; set; }
public double saldo { get; set; }
public static List<cuentaBancaria> cuentas = new List<cuentaBancaria>()
{
new cuentaBancaria ("John Doe", "123456", 1.5, 159),
new Tarjeta ("John Doe", "123456" , 1.5, 159, "123456789012", "John Doe", TipoTarjeta.CREDITO)
};
}
TipoTarjeta:
enum TipoTarjeta
{
CREDITO,
DEBITO,
MONEDERO,
FINANCIACION
}
Tarjeta:
class Tarjeta : cuentaBancaria
{
public Tarjeta()
{
}
public Tarjeta(string nombreCliente, string numCuenta, double tipoInteres, double saldo, string numTarjeta, string nombre, TipoTarjeta tipoTarjeta)
{
base.nombreCliente = nombreCliente;
base.numCuenta = numCuenta;
base.tipoInteres = tipoInteres;
base.saldo = saldo;
this.numTarjeta = numTarjeta;
this.nombre = nombre;
this.tipoTarjeta = tipoTarjeta;
}
public string numTarjeta { get; set; }
public string nombre { get; set; }
public TipoTarjeta tipoTarjeta { get; set; }
}
I want to return the elements that has a TipoTarjeta.XXX but when I try the
cuentas.Where(c => c.tipoTarjeta == tipo)
I get the error that is an element of the child (Tarjeta) not cuentaBancaria.
How can I only get those elements with that type?
You have a type mismatch.
Your function is declared such that it returns List<cuentaBancaria>, but Where is a LINQ extension method that returns an IEnumerable<cuentBancaria>.
To resolve your issue, add a call to the ToList() extension method as follows:
cuentas.Where(c => c.tipoTarjeta == tipo).ToList()
UPDATE
I copied your code to VSCode and this version of Main works for me. From what I could tell, you needed to reference cuentas through cuentaBancaria; also, the property you were referencing in the Where clause was incorrect, based on the class definition.
public static void Main()
{
var tipo = 3.15;
var result = cuentaBancaria.cuentas.Where(c => c.tipoInteres == tipo).ToList();
foreach (var item in result)
{
Console.WriteLine(item.tipoInteres);
}
}
You first need to filter the list to only the types of Tarjeta, and then you can filter by properties of Tarjeta. You can do this using .OfType<T>() in LINQ:
cuentas.OfType<Tarjeta>().Where(c => c.tipoTarjeta == tipo)

'Multiplicity constraint violated. The role 'Rayon_Produits_Source' of the relationship Rayon_Produits' has multiplicity 1 or 0..1.'

I would like to add many items to EF in order to put them to database, but I have this error (given in the title).
I searched on internet, but I only found some ideas based on the fact that an item can't be added twice, which seems logical. but I took care of giving different Ids (Id is the property which is the key in the associated table), but it does not work, I still have this error. By now, I have no idea of what could go wrong.
here are the datas I am trying to push to the database, after the different model classes:
the biggest container : Supermarche
[DataContract]
public class Supermarche
{
[Key]
[DataMember]
public int SupermarcheId { set; get; }
[DataMember]
public virtual ObservableCollection<Magasin> Magasins { set; get; }
}
it contains some "Magasin":
[DataContract]
public class Magasin : ElementSupermarche
{
[Key]
[DataMember]
public int MagasinId { set; get; }
[DataMember]
public string Nom { set; get; }
[DataMember]
public virtual ObservableCollection<Rayon> Rayons { set; get; }
}
which contains itself some "Rayon":
[DataContract]
public class Rayon : ElementSupermarche
{
[Key]
[DataMember]
public int RayonId { set; get; }
[DataMember]
public string Nom { set; get; }
[DataMember]
public virtual ObservableCollection<ProduitMagasin> Produits { set; get; }
}
which contains some "ProduitMagasin":
[DataContract]
public class ProduitMagasin : ElementSupermarche
{
[Key]
[DataMember]
public int ProduitMagasinId { set; get; }
[DataMember]
public string Nom { set; get; }
[DataMember]
public int Quantite { set; get; }
}
last, but not least, the filling part:
using (var ctx = new MarketContext("sqlserver"))
{
new MyDataInitializer().InitializeDatabase(ctx);
var produitMagasin1 = new ProduitMagasin() { Nom = "Pommes", Quantite = 10 };
var produitMagasin2 = new ProduitMagasin() { Nom = "Poires", Quantite = 5 };
var rayon1 = new Rayon() { RayonId = 1, Nom = "Fruits & légumes", Produits = new ObservableCollection<ProduitMagasin>() { produitMagasin1, produitMagasin2 } };
var produitMagasin5 = new ProduitMagasin() { Nom = "pizzas", Quantite = 4 };
var produitMagasin6 = new ProduitMagasin() { Nom = "quiches", Quantite = 8 };
var rayon3 = new Rayon() { RayonId = 2, Nom = "Surgelés", Produits = new ObservableCollection<ProduitMagasin>() { produitMagasin1, produitMagasin2 } };
var magasin1 = new Magasin() { Nom = "Auchan", Rayons = new ObservableCollection<Rayon>() { rayon1, rayon3 } };
ctx.SaveChanges();
var produitMagasin3 = new ProduitMagasin() { Nom = "melons", Quantite = 13 };
var produitMagasin4 = new ProduitMagasin() { Nom = "fraises", Quantite = 37 };
var rayon2 = new Rayon() { RayonId = 3, Nom = "Fruits & légumes", Produits = new ObservableCollection<ProduitMagasin>() { produitMagasin3, produitMagasin4 } };
var magasin2 = new Magasin() { Nom = "Carrefour", Rayons = new ObservableCollection<Rayon>() { rayon2 } };
var supermarche1 = new Supermarche() { Magasins = new ObservableCollection<Magasin> { magasin1, magasin2 } };
ctx.Supermarches.Add(supermarche1);
ctx.SaveChanges();
}
I don't think it is related, but here is the pull part which is in a WCF service and is executed right after the above code (in a different context, but there could be some time problem, maybe the computer reaches the pull part before having pushed the sample informations to the database:
using (var ctx2 = new MarketContext("sqlserver"))
{
ctx2.Configuration.ProxyCreationEnabled = false;
var sm = ctx2.Supermarches
.Include(s => s.Magasins.Select(mg => mg.Rayons.Select(r => r.Produits)))
.First();
return sm;
}
thank you
solved, the Rayon with RayonId=2 was containing the same Produits as the one with RayonId=1.

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.

JSON Parser Element not found

This is my JSON
{
"State of Origin 2014":{
"1471137":{
"EventID":1471137,
"ParentEventID":1471074,
"MainEvent":"State Of Origin Series 2014",
"Competitors":{
"ActiveCompetitors":3,
"Competitors":[
{
"Team":"New South Wales (2 - 1)",
"Win":"2.15",
},
{
"Team":"New South Wales (3 - 0)",
"Win":"3.05",
},
{
"Team":"Queensland (2 - 1)",
"Win":"3.30",
}
],
"TotalCompetitors":3,
"HasWinOdds":true
},
"EventStatus":"Open",
"IsSuspended":false,
"AllowBets":true
},
"3269132":{
"EventID":3269132,
"ParentEventID":0,
"MainEvent":"New South Wales v Queensland",
"Competitors":{
"Margin1Low":1,
"Competitors":[
{
"Name":"New South Wales",
"Win":"1.60",
},
{
"Name":"Queensland",
"Win":"2.35",
}
],
"HasWinOdds":true,
"TotalOddsColumns":2,
"MarketCount":1,
"PerformVideo":false
},
"EventStatus":"Open",
"IsSuspended":false,
"AllowBets":true
}
}
}
I am using JSON.Net and everything is working fine but in some of my data some element fields are missing for example i am getting Team element inside Competitors as
Teams = from JObject comps in value["Competitors"]["Competitors"]
select (string)comps["Team"]
But in some data Team element is missing and i want to grap Name Element so i am getting Object reference not set to an instance of an object. Error.
This is my code
var query =
from JProperty ev in obj.AsJEnumerable()
from JProperty evid in ev.Value.AsJEnumerable()
let value = (JObject)evid.Value
select new Person
{
EventID = (string)value["EventID"],
Description = (string)value["MainEvent"],
OutcomeDateTime = (string)value["OutcomeDateTime"],
EventStatus = (string)value["EventStatus"],
Teams = from JObject comps in value["Competitors"]["Competitors"]
select (string)comps["Team"]
};
foreach (var b in query)
{
string description = b.Description;
string OutcomeDateTime = b.OutcomeDateTime;
IEnumerable<string> _team = b.Teams;
foreach (var teams in _team)
{
string team = teams.ToString();
}
Console.WriteLine(description);
Console.WriteLine(OutcomeDateTime);
}
How can i get Name element value if Team element does not exist ?
You can deserialize your json to concrete classes
var obj = JsonConvert.DeserializeObject < Dictionary<string, Dictionary<string,RootObject>>>(json);
public class Competitor
{
public string Team { get; set; }
public string Win { get; set; }
}
public class CompetitorsClass
{
public int ActiveCompetitors { get; set; }
public List<Competitor> Competitors { get; set; }
public int TotalCompetitors { get; set; }
public bool HasWinOdds { get; set; }
}
public class RootObject
{
public int EventID { get; set; }
public int ParentEventID { get; set; }
public string MainEvent { get; set; }
public CompetitorsClass Competitors { get; set; }
public string EventStatus { get; set; }
public bool IsSuspended { get; set; }
public bool AllowBets { get; set; }
}
BTW: What is OutcomeDateTime? there is no such field in your json.
The following will work. Use the null-coalescing operator to grab "Name" if "Team" is null. http://msdn.microsoft.com/en-us/library/ms173224.aspx
Teams = from JObject comps in value["Competitors"]["Competitors"]
select (string)comps["Team"] ?? (string)comps["Name"]

Categories