Pick out a group of items using linq to xml - c#

My head is fuzzled with this. I have an xml doc which has the layout for a grid stored in it. If you notice the columns are stored as "Items" in the XML. I am trying to retrieve each "Item" out of the XML using LINQ but no matter what I do I keep taking on straggler properties that I don't need. Any help would be much appreciated.
<?xml version="1.0" encoding="utf-16" ?>
<DatagridView>
<ViewType>DevExpress.XtraGrid.Views.Grid.GridView</ViewType>
<ViewLayout>
<property name="Columns" iskey="true" value="9">
<property name="Item1" isnull="true" iskey="true">
<property name="VisibleIndex">0</property>
<property name="Visible">true</property>
<property name="Width">1249</property>
<property name="SummaryItem" isnull="true" iskey="true">
<property name="SummaryType">Count</property>
<property name="DisplayFormat">{0}</property>
<property name="FieldName">Comments</property>
<property name="Tag" isnull="true" />
</property>
<property name="Name">colComments</property>
<property name="ColumnEditName" />
<property name="FieldName">Comments</property>
</property>
<property name="Item2" isnull="true" iskey="true">
<property name="VisibleIndex">1</property>
<property name="Visible">true</property>
<property name="Width">197</property>
<property name="Name">colEvent</property>
<property name="ColumnEditName" />
<property name="FieldName">Event</property>
</property>
......
EDIT:
To be clear, the XML can contain any number of columns represented like so:
<property name="Item2" isnull="true" iskey="true">
<property name="VisibleIndex">1</property>
<property name="Visible">true</property>
<property name="Width">197</property>
<property name="Name">colEvent</property>
<property name="ColumnEditName" />
<property name="FieldName">Event</property>
</property>
I would like to grab those chunks of data in that same order via XML.

Well, you could just get the property elements directly beneath "Columns":
// TODO: Work out what to do if there are zero or multiple such elements
var columns = xdoc.Descendants("property")
.Where(x => (string) x.Attribute("name") == "Columns")
.Single();
var items = columns.Elements("property");
foreach (var item in items)
{
Console.WriteLine("Item {0}", (string) item.Attribute("name"));
foreach (var property in items.Elements("property"))
{
Console.WriteLine(" {0} = {1}", (string) item.Attribute("name"),
(string) item);
}
}

Related

Get value between xml tags having a "title" as value in name attribute?

I'm currently importing webparts using a file upload control containing collection of webPartDescription (XML)
<wrapper>
<webParts>
<webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
<metaData>
<type src="~/Web/Controls/Test/TestHeaderList.ascx" />
<importErrorMessage>Cannot import this Web Part.</importErrorMessage>
</metaData>
<data>
<properties>
<property name="UserCancelled" type="bool">False</property>
<property name="AllowedRoles" type="string" null="true" />
<property name="SourceFileName" type="bool">False</property>
<property name="ViewFilterExpression" type="string" />
<property name="UserCreated" type="bool">False</property>
<property name="HideExportButtons" type="bool">False</property>
<property name="RecordCount" type="bool">False</property>
<property name="TransferStatus" type="bool">False</property>
<property name="OrdersHeaderID" type="bool">False</property>
<property name="TransmitRecordCount" type="bool">False</property>
<property name="DataSource" type="Lobas.Demo.Web.Controls.Test+Views, Test.Demo.Web, Version=2.2.0.0, Culture=neutral, PublicKeyToken=null">None</property>
<property name="DeltaCount" type="bool">False</property>
<property name="OrdersHeaderBatchNo" type="bool">False</property>
<property name="DateCancelled" type="bool">False</property>
<property name="ResponseDescription" type="bool">False</property>
<property name="RunDate" type="bool">False</property>
<property name="DateCreated" type="bool">False</property>
<property name="ResponseCode" type="bool">False</property>
</properties>
<genericWebPartProperties>
<property name="Width" type="unit" />
<property name="Description" type="string" />
<property name="AllowEdit" type="bool">True</property>
<property name="ChromeType" type="chrometype">Default</property>
<property name="TitleIconImageUrl" type="string" />
<property name="Hidden" type="bool">False</property>
<property name="TitleUrl" type="string" />
<property name="AllowClose" type="bool">True</property>
<property name="AllowMinimize" type="bool">True</property>
<property name="AllowConnect" type="bool">True</property>
<property name="Height" type="unit" />
<property name="HelpMode" type="helpmode">Navigate</property>
<property name="Title" type="string">Orders Header List</property>
<property name="CatalogIconImageUrl" type="string" />
<property name="Direction" type="direction">NotSet</property>
<property name="AllowZoneChange" type="bool">True</property>
<property name="ChromeState" type="chromestate">Normal</property>
<property name="HelpUrl" type="string" />
<property name="AllowHide" type="bool">True</property>
<property name="ExportMode" type="exportmode">NonSensitiveData</property>
</genericWebPartProperties>
</data>
</webPart>
</webParts>
</wrapper>
i want to filter and fetch the value of property element inside "genericWebPartProperties" with attribute name ="Title"
eg : Orders Header List (in above xml)
i'm new to linq and xml. i tried several solutions but received null
My code behind looks like :
//Uploded xml containing multible webparts wraped under <wrapepr> root tag.
XDocument UploadedXmlWebparts = XDocument.Load(e.UploadedFile.FileContent);
// fetching individual webpart xml and storing in a Xelement Collection
var WebpartCollection = UploadedXmlWebparts.Root.Elements();
List<ClsImportWp> WebPartDescriptionList = new List<ClsImportWp>();
foreach (XElement webPart in WebpartCollection)
{
var TitleName = // Get the title tag value here
}
Use xml linq with a dictionary :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication166
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement genericWebPartProperties = doc.Descendants().Where(x => x.Name.LocalName == "genericWebPartProperties").FirstOrDefault();
XNamespace ns = genericWebPartProperties.GetDefaultNamespace();
Dictionary<string,string> dict = genericWebPartProperties.Elements(ns + "property")
.GroupBy(x => (string)x.Attribute("name"), y => (string)y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
}

Select attribute value from XDocument where another attribute equals specific string value

I have the following xml "example"
<methods>
<method name="listcust" >
<objects>
<object name="ExampleTest" type="" version="">
<properties>
<property name="FirstName" type="text">
<mappings>
<mapping type="property">
<property name="fn" />
</mapping>
</mappings>
</property>
<property name="LastName" type="text">
<mappings>
<mapping type="property">
<property name="ln" />
</mapping>
</mappings>
</property>
<property name="BirthDate" type="datetime">
<mappings>
<mapping type="property">
<property name="bd" />
</mapping>
</mappings>
</property>
</properties>
</object>
</objects>
</method>
</methods>
and Im trying to select the "name" atribute value of say
<property name="LastName" type="text">
when the "name" of the attribute within that element
is equal to "ln" <property name="ln" />
I tried the following
var query = from p in xdoc.Descendants("property")
where p.Descendants("property").Attributes("name").Contains(new XAttribute("name", "ln"))
select p.Attribute("name").Value;
var res = query.ToList<string>();
but I get zero results back.
If I break it down step by step
XDocument xdoc = XDocument.Parse(xml);
var props = xdoc.Descendants("property").Descendants("property");
var nameAtt = props.Attributes("name");
var contains = nameAtt.Contains(new XAttribute("name", "ln"));
Then I can see that nameAtt contains a list of the attributes including the <property name="ln" /> one but the contains bool is still false
If anyone can please point out the correct way of doing the select\where or perharps even a completely different more efficient way of retrieving the one attribute value where its child node attribute value equals the one passed in
Thanks
You just need to change the Where condition:
where p.Descendants("property").Any(x => (string)x.Attribute("name") == "In")
Any will check if there is any element that has name attribute equals to In

Nhibernate Queryover multi level model

lets say i have this database schema
[User] -1----n-> [Resource] -1----n-> [ResourceVersion]
and i want to select this using Nhibernate in one database roundtrip for user by username but select resourceVersions with future doesn work. How to hydrate collection of collections in one roundtrip using Futures? I prefer QueryOver or Criteria over HQL. I am using nHibernate 4.0.
public virtual User GetUserResources(string username)
using (ISession session = GetSession())
{
Resource resAlias = null;
User userAlias = null;
var result = session.QueryOver(() => userAlias)
.JoinQueryOver(x => x.Resources, () => resAlias)
.JoinQueryOver(() => resAlias.Versions)
.Where(() => userAlias.Login == username)
.Future<User>(); //THIS DOESNT WORK
var user = session.QueryOver<User>()
.Fetch(x => x.Resources).Eager
.Where(x => x.Login == username)
.SingleOrDefault<User>();//with this i can select user and resources
return user;
}
Mappings:
USER:
<class name="User" table="[User]">
<id name="Id" type="Int32">
<generator class="identity" />
</id>
<property name="Name">
<column name="Name" sql-type="varchar(100)" />
</property>
<property name="Email">
<column name="Email" sql-type="varchar(255)" />
</property>
<property name="Login">
<column name="Login" sql-type="varchar(50)" />
</property>
<property name="PasswordHash">
<column name="PasswordHash" sql-type="varchar(100)" />
</property>
<property name="CreateDate">
<column name="CreateDate" sql-type="datetime" />
</property>
<bag name="Resources" lazy="true" fetch="subselect" cascade="all-delete-orphan">
<key column="UserResource"/>
<one-to-many class="Resource" />
</bag>
</class>
RESOURCE:
<class name="Resource" table="[Resource]" abstract="true">
<id name="Id" type="Int64">
<generator class="identity" />
</id>
<discriminator column="Type"
not-null="true"
type="String" />
<bag name="Versions" cascade="all-delete-orphan" inverse="true" lazy="true" order-by="ActiveFrom DESC">
<key column="ResourceId" not-null="true"/>
<one-to-many class="Version"/>
</bag>
<subclass name="Resource1" discriminator-value="Res1" />
<subclass name="Resource2" discriminator-value="Res2" />
</class>
VERSION:
<class name="Version" table="Version">
<id name="Id" type="long">
<!--<column name="Id" sql-type="bigint"/>-->
<generator class="identity" />
</id>
...
<many-to-one name="Resource"
class="Resource"
column="ResourceId"/>
<property name="ActiveFrom">
<column name="ActiveFrom" sql-type="datetime" />
</property>
<property name="ActiveTo">
<column name="ActiveTo" sql-type="datetime"/>
</property>
...
Only query executed according to intelli trace in visual studio is this one:
SELECT this_.Id AS Id0_1_ ,
this_.Name AS Name0_1_ ,
this_.Email AS Email0_1_ ,
this_.Login AS Login0_1_ ,
this_.PasswordHash AS Password5_0_1_ ,
this_.CreateDate AS CreateDate0_1_ ,
resource2_.UserResource AS UserResource3_ ,
resource2_.Id AS Id3_ ,
resource2_.Id AS Id4_0_ ,
resource2_.Type AS Type4_0_
FROM
[User] this_ LEFT OUTER JOIN [Resource] resource2_
ON this_.Id
=
resource2_.UserResource
WHERE this_.Login
=
#p0;
and in #p0 is username i pass to method. No sign of versions at all which i find a little odd.
you are never iterating the IEnumerable returned by the future so it never executes it. I don't have NH 4.0 here right now but the following might work
public virtual User GetUserWithResources(string username)
{
using (ISession session = GetSession())
{
Resource resAlias = null;
return session.QueryOver<User>()
.Where(user => user.Login == username)
.Left.JoinQueryOver(x => x.Resources)
.Left.JoinQueryOver(res => res.Versions)
.TransformUsing(Transformers.DistinctRootEntity)
.List<User>().SingleOrDefault();
}
}

NHibernate collections: Update doesn't cascade

Currious behavior here. If I create a new HashCode, save the HashCode, then add a Transaction to the Transactions collection, the cascade is failing on Update. The Transaction object doesn't appear in the DB, and, curiously, the HashCode object's properties aren't updated either!
I have no idea what could be causing this. Here is the relevant mapping:
<class name="MyProject.HashCode, MyProject" table="HashCodes">
<id column="Id" name="Id">
<generator class="native" />
</id>
<many-to-one name="User" column="UserId" class="MyProject.User, MyProject" />
<property name="Hash" />
<property name="PasswordHash" />
<property name="InitialValue" update="false" />
<property name="CurrentValue" update="true" />
<property name="ClaimedDate" />
<property name="ClaimId" column="RowGuid" generated="insert" />
<bag name="Transactions" table="Transactions" cascade="all" inverse="true">
<key column="HashCodeId" />
<many-to-many column="Id" class="MyProject.Transaction, MyProject" />
</bag>
</class>
<class name="MyProject.Transaction, MyProject" table="Transactions">
<id column="Id" name="Id">
<generator class="native" />
</id>
<many-to-one name="HashCode" column="HashCodeId" class="MyProject.HashCode, MyProject" />
<property name="AmountCharged" />
<property name="AmountBilled" />
<property name="PreviousBalance" />
<property name="Memo" />
<property name="TransactionDate" generated="insert" update="false" />
</class>
Here is the test case that is failing, too, in case it's relevant:
[Test]
public void TransactionsCascadeWhenUpdatingHashCodes()
{
var user = TestFactory.CreateUser();
var hashCode = TestFactory.CreateHashCode(user);
var transaction = new Transaction
{
AmountBilled = hashCode.CurrentValue,
AmountCharged = decimal.Subtract(hashCode.CurrentValue, decimal.Multiply(hashCode.CurrentValue, 0.03M)),
HashCode = hashCode,
Memo = "This is a test",
PreviousBalance = hashCode.CurrentValue,
TransactionDate = DateTime.Now
};
hashCode.Transactions.Add(transaction);
// Now try to save it.
var hashCodeRepository = new HashCodeRepository(Session);
hashCodeRepository.Update(hashCode);
// Now see if that transaction is good to go
Assert.IsTrue(hashCode.Transactions[0].Id > 0);
// See if that transaction got persisted.
var loadedTransaction = Session.Load<Transaction>(hashCode.Transactions[0].Id);
Assert.IsNotNull(loadedTransaction);
}
// The repository method that is called...
public virtual void Update(TObj obj)
{
CurrentSession.Update(obj);
}
Anyone have any suggestions or ideas?
You are not flushing the session anywhere.
Change your update method to the following:
public virtual void Update(TObj obj)
{
using (ITransaction tx = CurrentSession.BeginTransaction())
{
CurrentSession.SaveOrUpdate(obj);
tx.Commit();
}
}

Delete throws "deleted object would be re-saved by cascade"

I have following model:
<class name="Person" table="Person" optimistic-lock="version">
<id name="Id" type="Int32" unsaved-value="0">
<generator class="native" />
</id>
<!-- plus some properties here -->
</class>
<class name="Event" table="Event" optimistic-lock="version">
<id name="Id" type="Int32" unsaved-value="0">
<generator class="native" />
</id>
<!-- plus some properties here -->
</class>
<class name="PersonEventRegistration" table="PersonEventRegistration" optimistic-lock="version">
<id name="Id" type="Int32" unsaved-value="0">
<generator class="native" />
</id>
<property name="IsComplete" type="Boolean" not-null="true" />
<property name="RegistrationDate" type="DateTime" not-null="true" />
<many-to-one name="Person" class="Person" column="PersonId" foreign-key="FK_PersonEvent_PersonId" cascade="all-delete-orphan" />
<many-to-one name="Event" class="Event" column="EventId" foreign-key="FK_PersonEvent_EventId" cascade="all-delete-orphan" />
</class>
There are no properties pointing to PersonEventRegistration either in Person nor in Event.
When I try to delete an entry from PersonEventRegistration, I get the following error:
"deleted object would be re-saved by cascade"
The problem is, I don't store this object in any other collection - the delete code looks like this:
public bool UnregisterFromEvent(Person person, Event entry)
{
var registrationEntry = this.session
.CreateCriteria<PersonEventRegistration>()
.Add(Restrictions.Eq("Person", person))
.Add(Restrictions.Eq("Event", entry))
.Add(Restrictions.Eq("IsComplete", false))
.UniqueResult<PersonEventRegistration>();
bool result = false;
if (null != registrationEntry)
{
using (ITransaction tx = this.session.BeginTransaction())
{
this.session.Delete(registrationEntry);
tx.Commit();
result = true;
}
}
return result;
}
What am I doing wrong here?
As far as I know, cascade="all-delete-orphan" belongs on the collection mapping element, not the many-to-one. You haven't shown the other two parts of your mapping so I can't say for sure but this is possible (likely) the problem.
I think Person should look something like:
<!-- other properties -->
<set name="Events" inverse="true" cascade="all-delete-orphan">
<key column="Person_id" />
<one-to-many class="PersonEventRegistration" />
</set>
Event:
<!-- similar mapping for Event -->
PersonEventRegistration:
<!-- other properties -->
<many-to-one name="Person" class="Person" column="PersonId" foreign-key="FK_PersonEvent_PersonId" cascade="delete" <!-- or many ="all" ? --> />
Actually, the above could be conflicting cascades (which might be what you have). So really, my answer is two things:
cascade="all-delete-orphan" has no meaning on many-to-one.
Make sure you have really thought-through how you are working with your entities and how they should cascade their operations.
Try de-referencing Person and Event in the delete:
public bool UnregisterFromEvent(Person person, Event entry)
{
var registrationEntry = this.session
.CreateCriteria<PersonEventRegistration>()
.Add(Restrictions.Eq("Person", person))
.Add(Restrictions.Eq("Event", entry))
.Add(Restrictions.Eq("IsComplete", false))
.UniqueResult<PersonEventRegistration>();
bool result = false;
if (null != registrationEntry)
{
using (ITransaction tx = this.session.BeginTransaction())
{
registrationEntry.Person = null;
registrationEntry.Event = null;
this.session.Delete(registrationEntry);
tx.Commit();
result = true;
}
}
return result;
}
Also, I wasn't aware that you could add a restriction on an object, I would have written this using aliases and IDs.
.Add(Restrictions.Eq("Person", person))
.Add(Restrictions.Eq("Event", entry))

Categories

Resources