I am developing an application with ASP.NET MVC using Visual Studio 2017 applying the Code First approach. I have three classes (tables) in the model and one repository named DataBase and an interface IDataBase.
I'm trying to store data in memory without using db. I don't now how to add new item in table?
This is my DataBase class (repository):
public class DataBase : IDataBase
{
private List<Proveedor> proveedors;
private List<Factura> facturas;
private List<FacturadeArticulo> facturadeArticulos;
public DataBase()
{
this.proveedors = new List<Proveedor>();
this.facturas = new List<Factura>();
this.facturadeArticulos = new List<FacturadeArticulo>();
}
public Proveedor AddProveedor(Proveedor item)
{
// acces db
if (item == null)
{
throw new ArgumentNullException("item");
}
proveedors.Add(item);
return item;
}
}
My interface IDataBase:
public interface IDatabase
{
Proveedor Add(Proveedor item);
}
My controller
public ActionResult Create(Proveedor provedor)
{
try
{
// TODO: Add insert logic here
var data = this.db.Add(provedor);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
I don't now how to implement Add method and save data in memory without using database.
Just for the case, the Entity Framework is not designed for using In-Memory storage.
To do this, you need to implement the appropriate ADO.NET provider: https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/data-providers
/**You can Save Data in XML file**/
//You can Save and load time by this method but it's slow process,
it may crash if data is large and system is slow, it stores data runtime
so takes RAM, its ok to use for few rows without any problem
//use the collection for storing data runtime
List<Person> pers = new List<Person>();
public class Person
{
public string id { get; set; }//1
public string name { get; set; }//2
public string bilno { get; set; }//3
public string mob { get; set; }//4
public DateTime dt { get; set; }//5
}
string path=#"c:\.....";
void save()
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load(path + #"\data.xml");
XmlNode xnode = xdoc.SelectSingleNode("Items");
xnode.RemoveAll();
foreach (Person i in pers)
{
XmlNode xtop = xdoc.CreateElement("Item");
XmlNode x1 = xdoc.CreateElement("a");
XmlNode x2 = xdoc.CreateElement("b");
XmlNode x3 = xdoc.CreateElement("c");
XmlNode x4 = xdoc.CreateElement("d");
XmlNode x5 = xdoc.CreateElement("e");
x1.InnerText = i.id;
x2.InnerText = i.name;
x3.InnerText = i.bilno;
x4.InnerText = i.mob;
x5.InnerText = i.dt.ToFileTime().ToString();
xtop.AppendChild(x1);
xtop.AppendChild(x2);
xtop.AppendChild(x3);
xtop.AppendChild(x4);
xtop.AppendChild(x5);
xdoc.DocumentElement.AppendChild(xtop);
}
xdoc.Save(path + #"\data.xml");
}
void load()
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load(path + #"\data.xml");
foreach (XmlNode xnode in xdoc.SelectNodes("Items/Item"))
{
Person p = new Person();
p.id = xnode.SelectSingleNode("a").InnerText;
p.name = xnode.SelectSingleNode("b").InnerText;
p.bilno = xnode.SelectSingleNode("c").InnerText;
p.mob = xnode.SelectSingleNode("d").InnerText;
p.dt = DateTime.FromFileTime(Convert.ToInt64(xnode.SelectSingleNode("e").InnerText));
}
}
Related
I'm making an application where I would connect signals with eachother. This creates a circular reference.
The examples I've seen show solutions for a Parent-Child structure. In my application I connect 2 objects from the same class with eachother, so I won't be able to simply ignore one of the references.
I've made a quick example of what my app is doing:
class Program
{
static void Main(string[] args)
{
Info i = new Info();
Employee bs = new Employee("asfdljfoiej", i);
Employee ss = new Employee("asfdljfj", i);
bs.conEm = ss;
ss.conEm = bs;
XmlSerializer xs = new XmlSerializer(typeof(Employee));
const string path = #"C:\Users\Joris.Bosma.KG\source\repos\TestProject\TestProject\bin\Debug\Serializing.xml";
TextWriter txtWriter = new StreamWriter(path);
xs.Serialize(txtWriter, bs);
txtWriter.Close();
//---------------------------------------------------------------------------------------------------------------------------------------
Program p = new Program();
p.Deserialize("Serializing.xml");
}
public void Deserialize(string filename)
{
XmlSerializer xs2 = new XmlSerializer(typeof(Employee));
Employee em;
using (Stream reader = new FileStream(filename, FileMode.Open))
em = (Employee)xs2.Deserialize(reader);
Console.Write(em.name);
}
}
public class Employee
{
public int Id = 1;
public String name = "John Smith";
public string subject = "Physics";
public string random;
public List<Employee> Employees;
public Employee conEm;
public Info inf;
public Employee()
{
}
public Employee(String s, Info i)
{
random = s;
inf = i;
}
}
public class Info : Employee
{
public string add = "Street";
}
The problem lays in
bs.conEm = ss
ss.conEm = bs
Thanks for helping in advance!
If structure of employees is not hierarchial (loops are possible), I would recommend to exclude properties 'conEm' and 'Employees' from serialization and store data in structure like this:
public class Relationship {
public int ParentId { get; set; }
public int ChildId { get; set; }
}
public class DataStore {
// flat list of employees
public List<Employee> Employees { get; set; }
// list of all relationship between Employees
public List<Relationship> Relationships { get; set; }
}
This structure needs to be populated before serialization.
After deserialization, structure can easily be restored:
var index = data.Employees.ToLookup(e => e.Id);
data.Relationships.Iter(r => {
var parent = index[r.ParentId].FirstOrDefault();
var child = index[r.ChildId].FirstOrDefault();
if (parent != nuu && child != null) {
parent.Employees.Add(child);
child.conEm = parent;
}
});
This is a sample xml. If a new font is to be added in the sense, all the existing fonts to be compare with the new font before adding to the preference.
How do I check the node(font) whether already exists or not in case of XmlDocument?
<preferences>
<font role="console">
<size>9</size>
<fname>Courier</fname>
</font>
<font role="default">
<fname>Times New Roman</fname>
<size>14</size>
</font>
<font role="titles">
<size>10</size>
<fname>Helvetica</fname>
</font>
</preferences>
Xnode has a feature called DeepEqual to compare nodes. XmlNode can be converted into Xnode by simple parsing.
XElement XmlElementToXElement(XmlNode e)
{
return XElement.Parse(e.OuterXml);
}
So, it will be easier from here. The method below will return true if two nodes are equal.
bool XmlNode_DeepEquals(XmlNode node1, XmlNode node2)
{
XElement tempX = XmlElementToXElement(node2);
XElement searchX = XmlElementToXElement(node1);
return XNode.DeepEquals(tempX, searchX))
}
This method is for comparing a list of Node.
bool isNodeAlreadyExists(XmlNode searchNode, XmlNodeList list)
{
bool exists = false;
foreach (XmlNode node in list)
{
if (XmlNode_DeepEquals(searchNode, node))
{
exists = true;
}
}
return exists;
}
One approach would be to create a couple of classes to represent the XML document and implement the IEquatable<T> Interface.
https://dotnetfiddle.net/QZFwDy
Classes for XML
[XmlRoot(ElementName = "font")]
public class Font : IEquatable<Font>
{
[XmlElement(ElementName = "size")]
public string Size { get; set; }
[XmlElement(ElementName = "fname")]
public string Fname { get; set; }
[XmlAttribute(AttributeName = "role")]
public string Role { get; set; }
public bool Equals(Font font)
{
if (font == null) return false;
return (Size == font.Size) && (Fname == font.Fname) && (Role == font.Role);
}
}
[XmlRoot(ElementName = "preferences")]
public class Preferences
{
[XmlElement(ElementName = "font")]
public List<Font> Font { get; set; }
}
Then use the Preferences class to deserialize the XML. Once the document is deserialized, leverage the List<T>.Contains(T item) method to see if the font node exists. The .Contains method will call the implementation of Equals in the Font class.
Code to Demonstrate
static void Main(string[] args)
{
Preferences preferences = null;
var xmlString = Data.XML;
using (var stream = new StringReader(xmlString))
{
var serializer = new XmlSerializer(typeof(Preferences));
preferences = (Preferences)serializer.Deserialize(stream);
}
var node0 = new Font()
{
Fname = "New One",
Role = "console",
Size = "12"
};
var node1 = new Font()
{
Fname = "Helvetica",
Role = "titles",
Size = "10"
};
if (preferences.Font.Contains(node0))
{
// Not expecting to enter here
Console.WriteLine($"'{nameof(node0)}' is already present");
}
if (preferences.Font.Contains(node1))
{
Console.WriteLine($"'{nameof(node1)}' is already present");
}
}
I have following table:
---------------------
Id Title Parent
---------------------
1 Parent NULL
2 Level_1 1
3 Level_2 1
4 Level_3 1
5 Level NULL
6 Level_New 5
Now I want to display these data in my console application, I know I need a recursive function but no idea how to do it becuase I want to read these data using ADO.NET not EntityFramework.In EF I could define a model that has a navigation property for children:
public class Menu
{
public int Id { get; set; }
public string Title { get; set; }
public int? Parent { get; set; }
public ICollection<Menu> Children { get; set; }
}
But the problem is that I don't want to use EF. I want to do it using raw ADO.NET
Recursion isn't fun, this is a solution that I used to test for a much larger recursion
public class MyObject
{
public string Id;
public string ParentId;
public string Name;
public string Comments;
}
a lot of this code you wont need, but this should give you want you need on recursion.
private void BindTree(IEnumerable<MyObject> list, TreeNode parentNode, string previousNode)
{
var myObjects = list as IList<MyObject> ?? list.ToList();
var nodes = myObjects.Where(x => (parentNode == null ? x.ParentId == "[].[].[(root)]" : x.ParentId == parentNode.Value));
var listOfNodeNames = new List<string>();
foreach (var node in nodes)
{
var newNode = new TreeNode(node.Name, node.Id);
BindTree(myObjects, newNode, previousNode);
}
}
The above code does the recursion I need ( code you wont need stripped out ) and builds a treeview on a page based on data from a datatable.
But, this should give you want you need to do your recursion.
You need to pull data from server first, then construct tree on client side. Beware of circular reference.
First, change your Menu class to ensure that Children will never null
public class Menu
{
public Menu()
{
Children = new HashSet<Menu>();
}
public int Id { get; set; }
public string Title { get; set; }
public int? Parent { get; set; }
public ICollection<Menu> Children { get; private set; }
}
Then pull the data from database, and construct the tree
var connBuilder = new SqlConnectionStringBuilder();
connBuilder.DataSource = "localhost";
connBuilder.InitialCatalog = "YourDatabaseName";
connBuilder.IntegratedSecurity = true;
using (var con = new SqlConnection(connBuilder.ToString()))
{
con.Open();
var list = new List<Menu>();
//pull data from database
using (var cmd = con.CreateCommand())
{
cmd.CommandText = "SELECT Id, Title, Parent FROM [dbo].[YourTableName]";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
list.Add(new Menu
{
Id = reader.GetInt32(0),
Title = reader.GetString(1),
Parent = reader.IsDBNull(2) ?(int?) null : reader.GetInt32(2)
});
}
}
}
//construct tree
var newList = new List<Menu>();
foreach (var l1 in list)
{
if (l1.Parent == null)
{
newList.Add(l1);
}
foreach (var l2 in list)
{
if (l2.Parent == l1.Id)
{
l1.Children.Add(l2);
}
}
}
// do whatever you want with newList
}
You will get data like this
I have set up a program that gets my weather for 1 day fine, but I have no idea how to get the other 4 days information because on the xml file the days all have the same name. How do I access the information from the different days?
http://weather.yahooapis.com/forecastrss?w=2473224 The Xml i am using
Code:
string query = String.Format("http://weather.yahooapis.com/forecastrss?w=2473224");
XmlDocument wData = new XmlDocument();
wData.Load(query);
XmlNamespaceManager manager = new XmlNamespaceManager(wData.NameTable);
manager.AddNamespace("yweather", "http://xml.weather.yahoo.com/ns/rss/1.0");
XmlNode channel = wData.SelectSingleNode("rss").SelectSingleNode("channel");
XmlNodeList nodes = wData.SelectNodes("/rss/channel/item/yweather:forecast", manager);
string temperature = channel.SelectSingleNode("item").SelectSingleNode("yweather:condition", manager).Attributes["temp"].Value;
string condition = channel.SelectSingleNode("item").SelectSingleNode("yweather:condition", manager).Attributes["text"].Value;
string humidity = channel.SelectSingleNode("yweather:atmosphere", manager).Attributes["humidity"].Value;
string WindSpeed = channel.SelectSingleNode("yweather:wind", manager).Attributes["speed"].Value;
string town = channel.SelectSingleNode("yweather:location", manager).Attributes["city"].Value;
string tfcond = channel.SelectSingleNode("item").SelectSingleNode("yweather:forecast", manager).Attributes["text"].Value;
string tfhigh = channel.SelectSingleNode("item").SelectSingleNode("yweather:forecast", manager).Attributes["high"].Value;
string tflow = channel.SelectSingleNode("item").SelectSingleNode("yweather:forecast", manager).Attributes["low"].Value;
Well I figured it out by assigning the values to an array like this and using some of the code like this.
var fiveDays = channel.SelectSingleNode("item").SelectNodes("yweather:forecast", manager);
foreach (XmlNode node in fiveDays)
{
var day = node.Attributes["day"].Value;
dayarray[i] = (day);
//
var text = node.Attributes["text"].Value;
textarray[i] = (text);
Thanks for all your help!
I believe you can use the XmlNode.SelectNodes method instead of SelectSingleNode.
This will return a list that you can then iterate through and copy the values to where you need them.
var fiveDays = channel.SelectSingleNode("item").SelectNodes("yweather:forecast", manager);
foreach (XmlNode node in fiveDays)
{
var text = node.Attributes["text"].Value;
var high = node.Attributes["high"].Value;
var low = node.Attributes["low"].Value;
}
This will give you a collection of the upcoming days, you can then loop over them to get the details on each day:
var upcomingDays = channel.SelectSingleNode("item").SelectNodes("yweather:forecast", manager);
foreach(XmlNode d in upcomingDays)
{
//d.Attributes["day"].Value;
}
I ran this in LINQPad and it worked fine.
This is much easier if you use a deserializer like XmlSerializer and classes. With the following classes:
[XmlRoot("rss")]
public class RssRoot
{
[XmlElement("channel")]
public Channel Channel { get; set; }
}
public class Channel
{
[XmlElement("item")]
public Item Item { get; set; }
// add other properties, if relevant
}
public class Item
{
[XmlElement("title")]
public string Title { get; set; }
[XmlElement("forecast", Namespace="http://xml.weather.yahoo.com/ns/rss/1.0")]
public List<Forecast> Forecasts { get; set; }
// add other properties, if relevant
}
public class Forecast
{
[XmlAttribute("text")]
public string Text { get; set; }
// add other attributes, if relevant
}
This will get your data from the URL in query
string query = "http://weather.yahooapis.com/forecastrss?w=2473224";
using (var reader = XmlReader.Create(query))
{
var ser = new XmlSerializer(typeof(RssRoot));
var rss = (RssRoot)ser.Deserialize(reader);
// use rss
}
If you want to continue to work with the XML using XmlDocument, you should use SelectNodes to get multiple forecast nodes, instead of getting a single node.
I have a C# MVC application which I need to output the following data to a view:
<versions>
<product>true</product>
<type>city</type>
<factory name="Demme" url="http://test1.com" thumbnail="http://test3.com/img1" interval="10" />
<factory name="Vollick" url="http://test2.com" thumbnail="http://test3.com/img1" interval="10" />
<factory name="Tony" url="http://test3.com" thumbnail="http://test3.com/img1" interval="10" />
</versions>
The above data comes from a SQL table/column which stores the data as a XML data type.
Can somone give me a code example to extract the values of the elements(maybe assign each value to variable) so I can pass it to a view?
So I need to get the values "true" , "City", "Demme" , "http://test1.com", "http://test3.com/img1....and so on.
Whats the best way to present this data to a view?
My idea is to create classes, corresponding to your Xml file, a Version class, a Factory class. Load the xml file, and then pass it to your class that return your data, here is how I do it :
The Version class :
public class Version
{
public bool IsProduct { get; set; }
public string City { get; set; }
public List<Factory> Factories { get; set; }
//Create a version
public Version(XElement xVersion)
{
IsProduct = Convert.ToBoolean(xVersion.Element("Product").Value);
City = xVersion.Element("City").Value;
Factories = Factory.GetFactories(xVersion);
}
//Get the list of versions
public static List<Version> GetVersions(XElement xDocument)
{
if (xDocument == null)
return null;
List<Version> list = new List<Version>();
var xVersions = xDocument.Elements("Version");
foreach (var xVersion in xVersions)
{
list.Add(new Version(xVersion));
}
return list;
}
}
The Factory class :
public class Factory
{
public string Name { get; set; }
public string Url { get; set; }
public string Thumbnail { get; set; }
public string Interval { get; set; }
//Create a factory
public Factory(XElement xFactory)
{
Name = xFactory.Attribute("Name").Value;
Url = xFactory.Attribute("Url").Value;
Thumbnail = xFactory.Attribute("Thumbnail").Value;
Interval = xFactory.Attribute("Interval").Value;
}
//Get the factories of a version
public static List<Factory> GetFactories(XElement xVersion)
{
var xFactories = xVersion.Elements("Factory");
if (xFactories == null)
return null;
List<Factory> list = new List<Factory>();
foreach (var xFactory in xFactories)
{
list.Add(new Factory(xFactory));
}
return list;
}
}
And last, in your MCV Controller :
private void myMethod()
{
var xDocument = XElement.Load("XmlFilePath");
var versions = Version.GetVersions(xDocument);
//And then, pass the -versions- to your typed view ^^
}
using System.Xml;
List<string> values= new List<string>();
XmlTextReader reader = new XmlTextReader ("books.xml");
while (reader.Read())
{
switch (reader.NodeType)
{
while (reader.MoveToNextAttribute()) // Read the attributes.
values.add(reader.Value);
break;
case XmlNodeType.Text: //Display the text in each element.
values.add(reader.Value);
break;
case XmlNodeType. EndElement: //Display the end of the element.
Console.WriteLine(">");
break;
}
}
Now you have a list of values. Assign it to the model and then use the model to populate the view.