How to create objects based upon element or attribute - c#

Need help in parsing the following XML. I am a newbie to Linq to XML.
I want to parse all picture data in a single objects array, and I dont seem to find a way,
Here is a sample xml,
<Object type="System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="Form1" children="Controls">
<Object type="System.Windows.Forms.PictureBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="PictureBox1" children="Controls">
<Property name="TabIndex">0</Property>
<Property name="Size">206, 152</Property>
<Property name="ImageLocation">C:\Documents and Settings\Administrator\Desktop\logo2w.png</Property>
<Property name="Location">41, 68</Property>
<Property name="TabStop">False</Property>
<Property name="Name">PictureBox1</Property>
<Property name="DataBindings">
<Property name="DefaultDataSourceUpdateMode">OnValidation</Property>
</Property>
</Object>
<Object type="System.Windows.Forms.PictureBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="PictureBox2" children="Controls">
<Property name="TabIndex">0</Property>
<Property name="Size">206, 152</Property>
<Property name="ImageLocation">C:\Documents and Settings\Administrator\Desktop\logo2w.png</Property>
<Property name="Location">42, 68</Property>
<Property name="TabStop">False</Property>
<Property name="Name">PictureBox2</Property>
<Property name="DataBindings">
<Property name="DefaultDataSourceUpdateMode">OnValidation</Property>
</Property>
</Object>
</Object>
I want to access the value as PictureObjects[0].Location = 41, 68, PictureObjects[1].Location = 42, 68 etc, Can I do it?
I saw several samples where I can create such objects based on the node name, and not based on the nodes attribute value? C# LINQ with XML, cannot extract multiple fields with same name into object
Can someone guide or let me know if its feasible?

You can start with this, code below just select TabIndex and Size properties, obviously adding other would not be a tricky:
XDocument xdoc = XDocument.Load(#"path to a file or use text reader");
var tree = xdoc.Descendants("Object").Skip(1).Select(d =>
new
{
Type = d.Attribute("type").Value,
Properties = d.Descendants("Property")
}).ToList();
var props = tree.Select(e =>
new
{
Type = e.Type,
TabIndex = e.Properties
.FirstOrDefault(p => p.Attribute("name").Value == "TabIndex")
.Value,
Size = e.Properties
.FirstOrDefault(p => p.Attribute("name").Value == "Size")
.Value
});

Related

C# NHibernate StaleObjectStateException

I have a MySQL database linked with NHibernate.
I am getting a StaleObjectStateException:
Message : Test method DALTest.UnitTest1.AddingResultAndGetAll threw
exception: NHibernate.StaleObjectStateException: Row was updated or
deleted by another transaction (or unsaved-value mapping was
incorrect): [Domain.Bean.Result#3]
...here on the rr.Save call :
DateTime date = new DateTime();
rr = new ResultRepository();
FootRace foot = new FootRace(2,"une courseeee", "vraiment une chouette course", date, 5, false);
Participant part = new Participant(2,"Boveeé", "Joseeé", 123, "M", date, 5);
rr.Save(new Result(3,foot,part , new TimeSpan(2500),5));
Where my Interface implementation is :
public void Save(Result result) {
var e =Session.GetSessionImplementation().PersistenceContext.EntityEntries;
Session.SaveOrUpdate(result);
Session.Flush();
}
After doing some research it looks like it's a thread problem but I can't find a solution to this. By the way the database is resetted at the moment i call this test, so there is absolutely nothing inside.
Here is the XML mapping file:
<class name="Result" table="result">
<id name="Id" column="idResult" type="int">
<generator class="native"></generator>
</id>
<many-to-one name="FootRace" class="FootRace" column="idFootRace" cascade="save-update"/>
<many-to-one name="Participant" class ="Participant" column ="idParticipant" cascade="save-update"/>
<property name="RaceTime" column="raceTime" not-null="false"/>
<property name="Rank" column="rank"/>
</class>

Reading NHibernate configuration file from C#

In my web application, I am using NHibernate configured by an xml file (nhibernate.cfg.xml). I need to read the connection string from that file in my C# code. My code is working, but I don't like it (in particular the foreach!) and I would like to query the xml file in a straight manner. I have tried to query it with link, but I always get null nodes.
Here is the cfg file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider
</property>
<property name="connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name="connection.connection_string">
Server=LEG\SQL12;initial catalog=DVR;user id=daniele;pwd=s;
</property>
<property name="dialect">
NHibernate.Dialect.MsSql2008Dialect
</property>
</session-factory>
</hibernate-configuration>
and here it is my C# code:
public static String GetConnectionString()
{
if (String.IsNullOrEmpty(_connectionString))
{
XElement root = XElement.Load("hibernate.cfg.xml");
var sessionFactoryNode = root.Elements().FirstOrDefault(); // session-factory
if (sessionFactoryNode != null)
{
var properties = sessionFactoryNode.Elements();
foreach (var property in properties)
{
if (property.Attribute("name").Value == "connection.connection_string")
_connectionString = property.Value.Trim();
}
}
}
return _connectionString;
}
How can I obtain the same result querying the xml?
XElement root = XElement.Load("hibernate.cfg.xml");
var connString = root.Descendants("property")
.Where(p => (string) p.Attribute("name") == "connection.connection_string")
.Select(p => (string) p)
.First();

How to convert linq query to Nhibernate's Criteria?

I am tying to rewrite a module which interacts with NHibernate. The buisness logic becomes more sofisticated and we decided to change our linq queries to Nhibernate's Criteria. Here is the old code:
nhSession.Query<User>().Where(
u => u.Roles.Contains(query.Role)
)
And the new code:
var criteria = nhSession.CreateCriteria<User>("user");
criteria.Add(/* contains? */);
And mapping:
<class name="User" table="users">
<id name="Id" column="id">
<generator class="hilo">
<param name="table">hilo</param>
<param name="column">user_id</param>
<param name="max_lo">10</param>
</generator>
</id>
<property name="Password" column="password" />
<bag name="Roles" table="user_roles">
<key column="user_id" />
<element column="role" />
</bag>
</class>
Where Roles is an enum.
How to make the query with Criteria behave like the Linq query?
var criteria = nhSession.CreateCriteria<User>("user");
var roleCriteria = criteria.CreateCriteria("Roles","roles");
roleCriteria.Add(Expression.Eq("role",Role.YourRole);
Assuming the user_roles table is mapped to a UserRole Class, and from this question, you may try something like :
DetachedCriteria dCriteria = DetachedCriteria.For<UserRole>("ur")
.SetProjection(Projections.Property("ur.UserId"))
.Add(Restrictions.EqProperty("ur.UserId", "user.Id"))
.Add(Restrictions.Eq("ur.Role", query.Role));
var criteria = nhSession.CreateCriteria<User>("user")
.Add(Subqueries.Exists(dCriteria)).List<User>();

Reading <property> tag

I was asked today to look at a new project - reading in some XML and doing some analysis. I know a little C#. I have gotten this far with this code that so far works. I get the 4 node lists successfully. I have a couple problems. First I am not sure how to access what is in the tag on any of the nodes in any of the lists. Second, I'd prefer to be able to use LINQ queries but XmlNodeList doesn't seem to support that syntax. In the sample XML below, I'd like to be able to get all the vdisks that belong to a particular IO Group or mdisk as determined by io_group_name or mdisk_grp_name property. Most of what I looked at gave examples for accessing the [Attribute] list and searches all used properties/atttributes interchanged.
What I tried is also below, it gave a null value exception. The Attributes list only has one attribute. I can't find any examples to do what I want and it isn't clear from inspecting the node in the debugger what I need to access to do what I want.
//this works
XmlTextReader reader = new XmlTextReader(_InputFile);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNodeList clusterlist = doc.SelectNodes("//object[#type='cluster']");
XmlNodeList controllerlist = doc.SelectNodes("//object[#type='controller']");
XmlNodeList mdisklist = doc.SelectNodes("//object[#type='mdisk']");
XmlNodeList vdisklist = doc.SelectNodes("//object[#type='vdisk']");
// this did not work - got null value exception
foreach (XmlNode vdisknode in vdisklist)
{
string str = vdisknode.Attributes["mdisk_grp_name"].Value;
}
A sample of the XML:
<object type="vdisk">
<property name="id" value="0" />
<property name="name" value="nim01_vd06_gmt" />
<property name="IO_group_id" value="0" />
<property name="IO_group_name" value="ossvc06_iogrp0" />
<property name="status" value="online" />
<property name="mdisk_grp_id" value="0" />
<property name="mdisk_grp_name" value="T1_OSIBM06_MDG1" />
<property name="capacity" value="644245094400" />
<property name="type" value="striped" />
</object>
object node has only one attribute: type
string type = vdiskNode.Attributes["type"].Value;
property node has two attributes: name and value:
string name = propertyNode.Attributes["name"].Value;
string value = propertyNode.Attributes["value"].Value;
What you need I deem is to extend the XPath query:
"//object[#type='vdisk']/property[#name='mdisk_grp_name']/#value"
Or use LINQ to XML:
from obj in doc.Load(xml).Root.Elements("object")
where (string)obj.Attribute("type") == "vdisk"
from prop in obj.Elements("property")
//where (string)prop.Attribute("name") == name
select prop.Value

Multiple conditions in HAVING clause with NHibernate Criteria?

I'm trying to use NHibernate's Criteria API to write the equivalent of this:
select foo_id from foo_history
group by foo_id
having sum(bar_in) > 0 or sum(baz_in) > 0;
with this mapping:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MVC"
namespace="MVC.Model.Things">
<class name="MVC.Model.Things.FooHistory, MVC"
table="foo_history">
<id name="ID" column="foo_hist_id" type="guid"
unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid.comb" />
</id>
<!-- Properties -->
<property name="BarIn" column="bar_in" type="decimal"
precision="19" scale="4" not-null="true" />
<property name="BazIn" column="baz_in" type="decimal"
precision="19" scale="4" not-null="false" />
<!-- Foreign Keys -->
<many-to-one name="Foo" column="foo_id"
class="MVC.Model.Things.Foo, MVC.Model.Things"
not-null="true" />
</class>
</hibernate-mapping>
and this Criteria code (Detached because it will be a subquery):
var results = DetachedCriteria.For<FooHistory>("fh")
.SetProjection(Projections.ProjectionList()
.Add(Projections.GroupProperty(Projections.Id()))
.Add(Projections.Sum("fh.BarIn"))
.Add(Projections.Sum("fh.BazIn")))
.Add(Restrictions.Gt(Projections.Sum("fh.BarIn"), 0) ||
Restrictions.Gt(Projections.Sum("fh.BazIn"), 0))
.GetExecutableCriteria(session).List();
The problem is that adding a conditional restriction after the SetProjection() results in NHibernate generating invalid MySQL:
SELECT this_.foo_hist_id as y0_,
sum(this_.bar_in) as y1_,
sum(this_.baz_in) as y2_
FROM foo_history this_
WHERE (sum(this_.bar_in) > ?p0
or sum(this_.baz_in) > ?p1)
GROUP BY this_.foo_hist_id
...using a WHERE instead of a HAVING. Using a single restriction works fine and everything is correct. I assume that since HN-1280 ("Adds HAVING support to CreateCriteria queries, Fixes parameter order bugs") this is possible but I'm not using the correct "OR" language (e.g., Restrictions.Disjunction() just always creates WHERE).
Is this possible?
I faced with this problem, however i don't think my workaround was good cause it doesn't work for example when you need ToRowCountQuery() for pagination. But anyway... You can use this class instead of built-in OrExpression
class OrHaving : OrExpression
{
public OrHaving(ICriterion lhs, ICriterion rhs) : base(lhs, rhs)
{
}
public override IProjection[] GetProjections()
{
return LeftHandSide.GetProjections().Concat(RightHandSide.GetProjections()).ToArray();
}
}
like
.Add(new OrHaving (Restrictions.Gt(Projections.Sum("fh.BarIn"), 0) ,
Restrictions.Gt(Projections.Sum("fh.BazIn"), 0)))

Categories