C# NHibernate StaleObjectStateException - c#

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>

Related

How to select only OData child elements

I'm building an OData application and I'm struggling on how to retrieve results and only include certain (child properties).
First, let me show you the registration in my builder:
builder.EntitySet<AggregatedArticlesSearchModel>("Search").EntityType.HasKey(x => x.Name);
Now, on to the model that I'm returning from my Query:
<EntityType Name="AggregatedArticlesSearchModel">
<Key>
<PropertyRef Name="Name"/>
</Key>
<Property Name="Name" Nullable="false" Type="Edm.String"/>
<Property Name="Values" Type="Collection(Zevij_Necomij.Mobile.App.Api.Models.OccurenceViewModel)"/>
</EntityType>
<ComplexType Name="OccurenceViewModel">
<Property Name="Value" Type="Edm.String"/>
<Property Name="Count" Nullable="false" Type="Edm.Double"/>
<Property Name="Articles" Type="Collection(Zevij_Necomij.Mobile.App.Api.Models.AggregatedArticleDescriptionViewModel)"/>
</ComplexType>
<ComplexType Name="AggregatedArticleDescriptionViewModel">
<Property Name="Name" Type="Edm.String"/>
<Property Name="Specification" Type="Edm.String"/>
<Property Name="Brand" Type="Edm.String"/>
</ComplexType>
When I'm executing a request to get the data, I'm not doing anything fancy but just returning the results from the database:
public async Task<IHttpActionResult> Get()
{
// Create all the managers for the platform context that are required by the application.
var classificationManager = Context.CreateManager(typeof(AggregatedArticleManager<>)) as AggregatedArticleManager<IAggregatedArticleStore<AggregatedArticle>>;
var classifications = await classificationManager.GetAllAsync();
var returnList = classifications.OrderBy(x => x.Name).Select(AggregatedArticlesSearchModel.MapFromDbModel).ToList();
return Ok(returnList.AsQueryable());
}
Since I'm working with child objects, the list can get quite huge:
{
"#odata.context": "http://api.mobileapp.appserver.dev.dsoft.be/OData/$metadata#Search",
"value": [
{
"Name": "(Veiligheids)slipkoppeling",
"Values": [
{
"Value": "ja",
"Count": 118,
"Articles": [
{
"Name": "230 V Sleuvenzaag",
"Specification": "Compacte machine",
"Brand": "Makita"
},
{
"Name": "230V Cirkelzaag SJS",
"Specification": "Softstart voor
},
}
}
I can have a thousand articles in a single set, thus, way to much to return over the Web Api.
Since I don't need all those properties in a single request, I was thinking to let the cliënt only retrieve child properties by using the ?$select parameter, thus the cliënts can say for example:
OData/Search?$select=Values
The problem here is that I for example, only want to return the Count, thus, I tought that a request like this was possible:
OData/Search?$select=Values/Count
However, this leads to an OData error: "The query specified in the URI is not valid. Found a path with multiple navigation properties or a bad complex property path in a select clause. Please reword your query such that each level of select or expand only contains either TypeSegments or Properties."
Anyone who has an idea on how to solve this one?
#Complexity
As I know, to select a sub property in a property is not supported.
However, if you build the OccurenceViewModel as entity type, then you can use the nested $select in $expand to meet your requirement.
For example:
1) build the entity type
builder.EntitySet<OccurenceViewModel>("ViewModels").EntityType.HasKey(x => x.Value);
then, Values in AggregatedArticlesSearchModel should be a navigation property.
2) Now, you can issue a GET request as follows to only return the Count property:
GET ~/odata/Search?$select=Values&$expand=Values($select=Count)
Then, the payload should look like the below:
{
"#odata.context":"http://localhost/odata/$metadata#Search(Values,Values(Count))","value":[
{
"Values":[
{
"Count":101.0
},{
"Count":102.0
}
]
},{
"Values":[
{
"Count":101.0
},{
"Count":102.0
}
]
}
]
}
Hope it can help you. Thanks.

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>();

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)))

How to create objects based upon element or attribute

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
});

Categories