I need to add data to view model using LINQ
My view model is :
public class SearchScrapViewModel
{
public WClass wClass{get; set;}
public SClass sClass{get; set;}
public YClass yClass { get; set; }
}
public class WClass
{
public string title { get; set; }
public string link { get; set; }
}
public class SClass
{
public string title { get; set; }
public string link { get; set; }
}
public class YClass
{
public string title { get; set; }
public string link { get; set; }
}
and i need to use these 3 classes with 3 different LINQ query and then pass data to return View(SearchScrapViewModel);
var wikians = //LINQ Logic
select new SearchScrapViewModel
{
wClass.link = link.Attributes["href"].Value, //Error: I am not able to add to wClass
wClass.title = link.InnerText
};
and similarly to other classes
and then pass to return View(SearchScrapViewModel); so that i can access all the 3 classes in View of this controller
How to do that?
You forgot to create an instance of your WClass:
select new SearchScrapViewModel {
wClass = new WClass {
link = link.Attributes["href"].Value,
title = link.InnerText
}
};
Alternatively, you could make WClass (and SClass and YClass) a struct instead of a class, then you don't need to instantiate it. In that case, however, you should probably make the struct immutable.
LINQ is not the be-all-end-all, and I dont know that this is the best approach for what you are looking for. I would suggest looking at the Builder Pattern, to accomplish this. If you really want to, you could do this in one LINQ query (using object initializers), but it might not read as clean as a builder would (but that is my two cents):
select new SearchScrapViewModel
{
wClass = new wClass{title = xyz, link = xyz},
sClass = new sClass...
yClass = new yClass...
}
It is not clear to me why you need a select statement in your example. In any case you can't return SearchScrapViewModel as your return because that is a type and not the instance. Unless your code is simplified for this post and you do need linq, I would suggest:
var wikians =
new SearchScrapViewModel {
wClass = new WClass {
link = link.Attributes["href"].Value,
title = link.InnerText
}
};
return View(wikians);
Related
I'm having a lot of trouble parsing an XML document into my custom classes. I've tried to read what I can find on the web and on here, but I'm still not getting anywhere. I'm working on a real estate app, and am trying to model a basic property where you have:
1 property
1 property can have multiple buildings
Each building can have multiple tenants.
I decided to try to store the data in an xml document, and I made an example as follows:
<?xml version="1.0" encoding="UTF-8"?>
<Property>
<Name>Grove Center</Name>
<Building>
<Name>Building1</Name>
<Tenant>
<Name>Tenant1</Name>
<SquareFeet>2300</SquareFeet>
<Rent>34000</Rent>
</Tenant>
<Tenant>
<Name>Tenant2</Name>
<SquareFeet>3100</SquareFeet>
<Rent>42000</Rent>
</Tenant>
<Tenant>
<Name>Tenant3</Name>
<SquareFeet>1700</SquareFeet>
<Rent>29000</Rent>
</Tenant>
</Building>
<Building>
<Name>Building2</Name>
<Tenant>
<Name>Tenant1</Name>
<SquareFeet>6150</SquareFeet>
<Rent>80000</Rent>
</Tenant>
<Tenant>
<Name>Tenant2</Name>
<SquareFeet>4763</SquareFeet>
<Rent>60000</Rent>
</Tenant>
</Building>
</Property>
Actually my first question is if this format is even correct.. I saw some xml examples where they added an extra tag such as <buildings> before they started listing out the individual <Building> tags for each building. Is that necessary? The W3C examples I saw didn't do it that way.. but this post on stackexchange was pretty close to what im doing: Parsing XML with Linq with multiple descendants
Here is the code for my classes in C#:
public class Property
{
public string Name { get; set; }
public List<Building> Buildings = new List<Building>();
}
public class Building
{
public string Name { get; set; }
public List<Tenant> Tenants = new List<Tenant>();
}
public class Tenant
{
public string Name { get; set; }
public int SF { get; set; }
public decimal Rent { get; set; }
}
I'm not sure if using the new keyword on my lists right in the class definition is good practice.. but I was getting errors trying to add a building or tenant to the list later on in my program so I didn't know what else to do. Right now I'm not much further in my main code than:
Property p = new Property();
XDocument doc = XDocument.Load(#"C:\Users\SampleUser\Desktop\sample-property.xml");
Any help is appreciated, thanks
Following query will give you the correct result:-
Property p = new Property
{
Name = (string)doc.Root.Element("Name"),
Buildings = doc.Root.Elements("Building")
.Select(x => new Building
{
Name = (string)x.Element("Name"),
Tenants = x.Elements("Tenant")
.Select(t => new Tenant
{
Name = (string)t.Element("Name"),
SF = (int)t.Element("SquareFeet"),
Rent = (decimal)t.Element("Rent")
}).ToList()
}).ToList()
};
Theres a few things you might want to change.
The property names must match the xml tags, or you have to specify the mapping manually. In your example code, Buildings and Tenants are declared as fields, you should change it to properties. If you want, you can then initialize them to empty list in the constructors:
public class Property
{
public string Name { get; set; }
[XmlElement("Building")]
public List<Building> Buildings { get; set; }
public Property()
{
Buildings = new List<Building>();
}
}
public class Building
{
public string Name { get; set; }
[XmlElement("Tenant")]
public List<Tenant> Tenants { get; set; }
public Building()
{
Tenants = new List<Tenant>();
}
}
public class Tenant
{
public string Name { get; set; }
[XmlAttribute("SquareFeet")]
public int SF { get; set; }
public decimal Rent { get; set; }
}
Further, I would recommend deserializing the file rather than using linq. Consider these helper methods:
public static class XmlHelper
{
public static T DeserializeFromXmlString<T>(string xml)
{
var xmlSerializer = new XmlSerializer(typeof (T));
using (var stringReader = new StringReader(xml))
{
return (T) xmlSerializer.Deserialize(stringReader);
}
}
public static T DeserializeFromXmlFile<T>(string filename) where T : new()
{
return DeserializeFromXmlString<T>(File.ReadAllText(filename));
}
}
Deserialization is then easy:
var listOfProperties = XmlHelper.DeserializeFromXmlFile<Property>(#"C:\Users\SampleUser\Desktop\sample-property.xml");
Intializing your public fields with empty lists is perfectly fine and good practice to avoid the errors you got. If you do not initialize them, they are null, hence the errors.
You could use properties instead of fields for your lists however.
Starting with C# 6 you can use simplified auto-property assignment:
public List<Building> Buildings {get;set;} = new List<Building>();
For C# < 6 you can use auto properties and initialize the property within the constructor or use a property with backing field.
//Auto property with assignment in constructor
public class Property
{
public string Name { get; set; }
public List<Building> Buildings {get;set;};
public Property(){
Buildings = new List<Building>();
}
}
//Property with backing field
public class Property
{
private List<Building> _buildings = new List<Building>();
public string Name { get; set; }
public List<Building> Buildings {get {return _buildings;} set {_buildings = value;}};
}
For reading XML and creating the object graph, you can use LINQ in conjuction with object initializers.
Func<IEnumerable<XElement>, IEnumerable<Tenant>> getTenants = elements => {
return elements.Select (e => new Tenant {
Name = e.Element("Name").Value,
Rent = decimal.Parse(e.Element("Rent").Value),
SF = int.Parse(e.Element("SquareFeet").Value)
});
};
Func<IEnumerable<XElement>, IEnumerable<Building>> getBuildings = elements => {
return elements.Select (e => new Building{
Name = e.Element("Name").Value,
Tenants = getTenants(e.Elements("Tenant")).ToList()
});
};
//xdoc is your parsed XML document
//e.g. var xdoc = XDdocument.Parse("xml contents here");
var property = new Property{
Name = xdoc.Root.Element("Name").Value,
Buildings = getBuildings(xdoc.Root.Elements("Building")).ToList()
};
ok so this is maybe very simple but I just can not see where I am going wrong so any help is grateful
I have a model of this:
public IEnumerable<SelectedProfiels> profiles { get; set; }
public class SelectedProfiels
{
public int Identifer { get; set; }
public string ProfileName { get; set; }
}
and then I am trying to read from this
i am then building an array called selectedProfiles,
I then have this code
var pro = from s in selectedProfiles select s;
What im wanting to do is find all the ProfileName's and assigned them there on ViewBag.[i] or just there own string variable
I have a model collection like this
var userd = new User()
{
ID = i.FirstOrDefault(),
Type = t.FirstOrDefault(),
AuthorityLevel = a.FirstOrDefault(),
Language = l.FirstOrDefault(),
Profiles = pro,
};
public IEnumerable<SelectedProfiels> profiles { get; set; }
public class SelectedProfiels
{
public int Identifer { get; set; }
public string ProfileName { get; set; }
}
I then pass userd to a new page:
return RedirectToAction("test", "Account", userd);
public ActionResult test (Userm)
{
ViewBag.d = m.profiles;
return View();
}
any help please
So, given your linq query:
var pro = from s in
selectedProfiles
select s;
You can use Linq to generate an IEnumerable from pro, like:
var selectedProfiles = pro.Select(p => p.ProfileName).ToList();
Then, you can use selectedProfiles to populate the array you desire:
string[] newStrings = selectedProfiles.ToArray();
Instead of
select s
Just use
select s.ProfileName
I have an object containing different properties like the object below:
public class CompressedLogResponse
{
public string LoggerType { get; set; }
public int NumberOfRegisters { get; set; }
public int NewLogId { get; set; }
public DateTime LoggerAnnounceTime { get; set; }
public List<Log> Log{ get; set; }
}
How can I return a List of this objekt that does not include the List<Log> Log property?
Linq would be preffered
Thanks for any help that you can provide
You cannot just hide a property of a class (you declared it a as public)
Option 1:
Althought as Robson wrote you can set it null (thats not very reliable thaught cause nobody expects a class containing a property that is always null)
Option2:
If you consume the class on the same place use a anonymous type as Mez wrote, althought it sounds like you want to hide the Property from external usage. (I don't like the dynamic approach, the dynamic keyword was made for interop/DOM not for transporting anonymous types.)
Option3:
If you want a List of this type to be returned without the Log property, you have to create a new class (Inheritance is a good way to realize this):
public class CompressedLogResponseBase
{
public string LoggerType { get; set; }
public int NumberOfRegisters { get; set; }
public int NewLogId { get; set; }
public DateTime LoggerAnnounceTime { get; set; }
}
public class CompressedLogResponse : CompressedLogResponseBase
{
public List<Log> Log{ get; set; }
}
Now you can return a list of base items (that do not have a Log property at all)
public List<CompressedLogResponseBase> ReturnWithoutLog(IEnumerable<CompressedLogResponse> items)
{
return ((IEnumerable<CompressedLogResponseBase>)items).ToList();
}
If a IEnumerable as return type is suficient it becomes really easy
public IEnumerable<CompressedLogResponseBase> ReturnWithoutLog(IEnumerable<CompressedLogResponse> items)
{
return items
}
whith "does not include the List Log property" i guess you mean that the property "public List Log" will be blanked but still there, so you can just null that property out, because if you create an object that doesn't contain the "public List Log" property, than it will not be a "CompressedLogResponse" but will be another type.
List<CompressedLogResponse> listOne = new List<CompressedLogResponse>();
//....
//fill the listOne
//....
List<CompressedLogResponse> listWithoutListLog = (from item in listOne
select new CompressedLogResponse(
LoggerType = item.LoggerType,
NumberOfRegisters = item.NumberOfRegisters ,
NewLogId = item.NewLogId ,
LoggerAnnounceTime = item.LoggerAnnounceTime ,
Log= null)).ToList();
You can return an anonymous list of your original list like the following;
public static List<dynamic> Test() {
List<CompressedLogResponse> list = new List<CompressedLogResponse>();
var result = list.Select(x => new
{
x.LoggerAnnounceTime,
x.LoggerType,
x.NewLogId,
x.NumberOfRegisters
});
return result.ToList<dynamic>();
}
Take a look at the .Select(), and also the dynamic keyword.
Then to call it,
var x = Test();
foreach(dynamic o in x)
{
int NumberOfRegisters;
//You have 2 ways... either by
NumberOfRegisters = o.NumberOfRegisters;
// or reflection
NumberOfRegisters = o.GetType().GetProperty("NumberOfRegisters").GetValue(o, null);
}
i have two classes as below i need to cast list<child> to list<BM>
public class Child
{
[JsonProperty("name")]
public string title { get; set; }
public string type { get; set; }
public string url { get; set; }
public List<Child> children { get; set; }
}
public class BM
{
public string title { get; set; }
public string type { get; set; }
public string url { get; set; }
public List<BM> children { get; set; }
}
You can't cast it. You can create new list with all items transformed from one class to another, but you can't cast the entire list at once.
You should probably create a method which will transform Child into BM instance:
public static BM ToBM(Child source)
{
return new BN() {
title = source.title,
type = source.type,
url = source.url,
children = source.children.Select(x => ToBM(x)).ToList()
};
}
and then use LINQ to transform entire list:
var BMs = source.Select(x => ToBM(x)).ToList();
use automapper's DLL. You can read more about automapper at http://automapper.codeplex.com/wikipage?title=Lists%20and%20Arrays
List<BM> BMList=
Mapper.Map<List<Child>, List<BM>>(childList);
same question has been asked before
Automapper copy List to List
You can also use Custom Type Conversions if you want to cast between custom types like that:
Class2 class2Instance = (Class2)class1Instance;
So all you need is to define explicit or implicit conversion function in your child class.
// Add it into your Child class
public static explicit operator BM(Child obj)
{
BM output = new BM()
{
title = obj.title,
type = obj.type,
url = obj.url,
children = obj.children.Select(x => BM(x)).ToList()
};
return output;
}
and then:
var result = source.Select(x => (BM)x).ToList();
I am a new to C#, I need a small help on how can I pass multiple parameters between the classes?
Below is a small example but my parameters will more than the 10. Is there another way to this?
public StreamStructure(String name, string id, string classname, int number)
{
this.name = name;
this.id = id;
this.classname = classname;
this.number = number;
}
List ------
List<abc> don = new List<abc>();
foreach (XmlElement abc_cdb in abc_cdbs)
{
abc.Name = abc_cdb.GetAttribute("NAME");
abc.Id = abc_cdb.GetAttribute("id");
abc.Clssname = abc_cdb.GetAttribute("classname");
abc.number = Convert.ToInt32(abc_cdb.GetAttribute("number"));
don.Add(abc);
}
I have used as suggested in ans but I am trying to create a list in C# my first record gets replaced with the 2nd one, since the fields in MyDTO are defined as public. Do you have any idea how to fix this?
Sure, use DTO's (data transfer objects). That is, create a class that has all the fields you want to send and use an instance of it as a parameter. Added bonus is that your method signature won't change even if you change your DTO class.
You are probably better off using C# Initializers or a Data Transfer Object than a large number of constructor parameters. Or combine the two.
public class MyDTO
{
String Name { get; set; }
String Id { get; set; }
String ClassName { get; set; }
int Number { get; set; }
}
var MyDTO = new MyDTO()
{
Name = Name,
Id = Id,
ClassName = ClassName,
Number = Number
}
var stream = new StreamStructure(MyDTO)
To create a list of these objects as in your example, create a new DTO within the loop body.
var don = new List<MyDTO>();
foreach (XmlElement abc_cdb in abc_cdbs)
{
var abc = new MyDTO()
{
Name = abc_cdb.GetAttribute("NAME");
Id = abc_cdb.GetAttribute("id");
ClassName = abc_cdb.GetAttribute("classname");
Number = Convert.ToInt32(abc_cdb.GetAttribute("number"));
};
don.Add( abc );
}
You could pass a domain object that represents the item you are manipulating.
public class Widget
{
public string Name {get;set;}
public int Id {get;set;}
public string ClassName {get;set;}
public int Number {get;set;}
}
var myWidget = new Widget();
myWidget.Name = "Blue Widget";
//etc
StreamStructure(myWidget);
You should write a new class that contains the properties you want to pass to the method, and change your method to include just that new class.
For your example, write a new class like this:
public class RequestObject
{
public string Name { get; set; }
public string ID { get; set; }
public string ClassName { get; set; }
public int Number { get; set; }
}
Then change your method like this:
public StreamStructure(RequestObject requestObject)
{
//DoStuff
}