How to query Dynamic properties in NHibernate? - linq

I have this problem.
I have a class like this:
public class WfStep
{
private readonly IDictionary properties = new Hashtable();
public virtual Guid Id { get; private set; }
public virtual string Name { get; set; }
public virtual dynamic Properties { get { return new HashtableDynamicObject(properties); } }
and its mapping file like this:
<class name="ConsoleApplication4.WfStep" table="WFSteps">
<id name="Id">
<generator class="guid"/>
</id>
<property name="Name" />
<map name="Properties" table="WFSteps_Properties" access="field.lowercase">
<key column="StepId" />
<index column="PropertyName" type="System.String"/>
<composite-element class="ConsoleApplication4.ValueItem, ConsoleApplication4">
<property name="Value" type="System.String"/>
<property name="ValueType" type="System.String"/>
</composite-element>
</map>
This example is ported from:
Ayende Support dynamic fields with NHibernate and .NET 4.0
Then I save an object to the db like this:
ie.
var step = new WfStep { Name = "John" };
var property = new ValueItem() { Value = DateTime.Now, ValueType = "System.DateTime" };
step.Properties["DateProperty"] = property ;
Session.Save(step);
Now I want to return all the WFSteps that have DateProperty set to year 2010 ie.:
var Session.Query<WfStep>().Where(x=>x.Properties.DateProperty.Year == 2010);
It throws an error:
An expression tree may not contain a dynamic operation
How can I query this type of class that has Dynamic properties.?

You can index collections mapped as a map or as list. Try the following hql
from WfStep s
where s.Properties["DateProperty"] = "2010"

Related

using foreign keys with MudDataGrid

I have the following object:
`
public class Permissions : Item
{
public int Id { get; set; }
public AppUser User { get; set; }
public Component Component { get; set; }
public string Permission { get; set; }
}
`
My MudDataGrid:
`
<MudDataGrid T="Permissions" Items="#permissions" ReadOnly="#_readOnly" EditMode="#(_isCellEditMode ? DataGridEditMode.Cell : DataGridEditMode.Form)"
StartedEditingItem="#StartedEditingItem" CancelledEditingItem="#CancelledEditingItem" CommittedItemChanges="#CommittedItemChanges"
Bordered="true" Dense="true" EditTrigger="#(_editTriggerRowClick ? DataGridEditTrigger.OnRowClick : DataGridEditTrigger.Manual)">
<Columns>
<Column T="Permissions" Field="User" Title="UserName" IsEditable="false" />
<Column T="Permissions" Field="**Component.ComponentName**" IsEditable="false" />
<Column T="Permissions" Field="Permission" />
<Column T="Permissions" Hidden="#(_isCellEditMode || _readOnly || _editTriggerRowClick)" CellClass="d-flex justify-end">
<CellTemplate>
<MudIconButton Size="#Size.Small" Icon="#Icons.Outlined.Edit" OnClick="#context.Actions.StartEditingItem" />
</CellTemplate>
</Column>
</Columns>
`
both 'AppUser' and 'Component' are foreign keys to other objects. Data is returned fine, however I am having dificulty displaying these objects on the experimental MudDataGrid.
I know that the MudDataGrid isn't 'live' currently, but I'm only using it on a test system at present. Is anyone aware of a way for me to reference the items of the foreign object in the grid? I thought it would be something like 'Field="Component.ComponentName', but I get a nullreferenceexception.
I've tried 'Field="Component.ComponentName"' ,'Field="Component[ComponentName]"' to no avail.

Spring PropertyPlaceholderConfigurer and passing multiple queries at startup

I am working on some existing application and it loads single DB query at server startup .
Now I want to pass more (may 3-4 queries) in same code instead one query.
i.e.How I can pass multiple queries in spring
Here is code-
myspring.xml
<property name="mypropertyfiles">
<list>
<value>test1.properties</value>
<value>test2.properties</value>
</list>
</property>
<bean id="mybean" class="com.test.MyBean">
<constructor-arg><ref-bean="mypropertyfiles"/><const-arg>
<constructor-arg><ref-bean="dataSource"/><const-arg>
<constructor-arg><value>select pcode, pname from PRODUCT1</value>
// Here only one query. **but I want to pass more queries like**
//select pcode, pname from PRODUCT2,
//select ocode, oname from ORDER1,
//select ocode, oname from ORDER2
<const-arg> <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
</bean>
MyBean.java
public class MyBean extends PropertyPlaceholderConfigurer
{
private DataSource dSource;
private String dbQuery;
// this is existing map to store PRODUCT1 table details
Map product1Map = new ConcurrentHashMap();
//lly, I will create more product2Map,order1Map , order2Map to store my
//queries data from PRODUCT2,ORDER1,ORDER2 tables
// here it is taking only one query.But I want more queries ie list
MyBean (Resource[] resources , DataSource dSource,String dbQuery){
super();
setLocations(resources);
this.dSource=dSource;
this.dbQuery=dbQuery;
}
#override
public String resolvePlaceholder(String p,Peroperties p){
//some code.....
loadQuery();
}
loadQuery(){
JdbcTemplate j;
j.execute(dbQuery,.......) // exsiting code has one query only{
public Map doInPreparestament(Preaprestatement ps){
rs =ps.executeQuery..
while(rs.next){
product1Map.put(rs.getString("pcode"),rs.getString("pname")); // only one map
}
}
}
}
Questions -
How I can pass multiple queries from "myspring.xml" file
I want to use existing loadQuery method to load all my queries and put into other Maps i.e. product2Map,order1Map ,order2Map

Map property value not getting set correctly in Spring

For my test bean Map property is not being set properly and null value is getting set which i find on debug.
Actually the bean has 3 properties and one of the property is a Map and rest are simple key value pairs.
The problem is that spring is setting 3 properties(from,html) correctly but is not setting the Map property ("to").
Below is the code and the solutions that i have tried. The "to" property of the EmailInfo class is getting set to null.
I have kept the constants in a property file and have used PropertyPlaceholderConfigurer.
I am sure there is no problem with the property file as the "from" property is getting set with the correct value.
<bean id="Info"
class="com.src.framework.EmailInfo"
scope="prototype">
<property name="to">
<!-- <map>
<entry key="DEV" value="${email.dev}" />
</map> -->
<util:map map-class="java.util.HashMap">
<entry key="DEV" value="${email.dev}"/>
</util:map>
</property>
<property name="from" value="${email.sender}" />
<property name="html" value="true" />
</bean>
The EmailInfo class
public class EmailInfo {
private boolean html;
private Map<String, String[]> to;
private String from;
public boolean isHtml() {
return this.html;
}
public void setHtml(boolean argHtml) {
this.html = argHtml;
}
public Map<String, String[]> getTo() {
return this.to;
}
public void setTo(Map<String, String[]> argTo) {
this.to = argTo;
}
public String getFrom() {
return this.from;
}
public void setFrom(String argFrom) {
this.from = argFrom;
}
}
Please provide your suggestions are to what i am doing wrong here and how to rectify it.
Try change signature of your map to Map<String,String> because it looks like you have not proper types in that map that you want to put it in xml.
But when you would like to have working your case with Map<String,String[]> you have change your xml
<util:list id="myList">
<value>foo</value>
<value>bar</value>
</util:list>
<util:map>
<entry key="DEV" value="myList"/>
</util:map>

Programmatic access to properties created by property-placeholder

I'm reading properties file using context:property-placeholder. How can I access them programatically (#Value doesn't work - I don't know property titles at the moment of developing)?
The main problem is I can't change applicationContext.xml file because it's setted up by "parent" framework
ps. It's strange but Environment.getProperty returns null
No you can't. PropertyPlaceholderConfigurer is a BeanFactoryPostProcessor, it is only "alive" during bean creation. When it encounters a ${property} notation, it tries to resolve that against its internal properties, but it does not make these properties available to the container.
That said: similar questions have appeared again and again, the proposed solution is usually to subclass PropertyPlaceHolderConfigurer and make the Properties available to the context manually. Or use a PropertiesFactoryBean
We use the following approach to access properties for our applications
<util:properties id="appProperties" location="classpath:app-config.properties" />
<context:property-placeholder properties-ref="appProperties"/>
Then you have the luxury of just autowiring properties into beans using a qualifier.
#Component
public class PropertyAccessBean {
private Properties properties;
#Autowired
#Qualifier("appProperties")
public void setProperties(Properties properties) {
this.properties = properties;
}
public void doSomething() {
String property = properties.getProperty("code.version");
}
}
If you have more complex properties you can still use ignore-resource-not-found and ignore-unresolvable. We use this approach to externalise some of our application settings.
<util:properties id="appProperties" ignore-resource-not-found="true"
location="classpath:build.properties,classpath:application.properties,
file:/data/override.properties"/>
<context:property-placeholder ignore-unresolvable="true" properties-ref="appProperties"/>
#Value
annotation works on new releases of Spring (tested on v3.2.2)
Here is how it is done:
Map your properties file in spring configuration file
<!--Import Info:
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd-->
<context:property-placeholder location="classpath:/app-config.properties" />
Create app-config.properties inside (root) your source folder
my.property=test
my.property2=test2
Create a controller class
#Controller
public class XRDSBuilder
{
#Value("${my.property}")
private String myProperty;
public String getMyProperty() { return myProperty; }
}
Spring will automatically map the content of my.property to your variable inside the controller
Mapping to a list
Property value:
my.list.property=test,test2,test3
Controller class configuration:
#Value("#{'${my.list.property}'.split(',')}")
private List<String> myListProperty;
Advanced mapping
#Component("PropertySplitter")
public class PropertySplitter {
/**
* Example: one.example.property = KEY1:VALUE1,KEY2:VALUE2
*/
public Map<String, String> map(String property) {
return this.map(property, ",");
}
/**
* Example: one.example.property = KEY1:VALUE1.1,VALUE1.2;KEY2:VALUE2.1,VALUE2.2
*/
public Map<String, List<String>> mapOfList(String property) {
Map<String, String> map = this.map(property, ";");
Map<String, List<String>> mapOfList = new HashMap<>();
for (Entry<String, String> entry : map.entrySet()) {
mapOfList.put(entry.getKey(), this.list(entry.getValue()));
}
return mapOfList;
}
/**
* Example: one.example.property = VALUE1,VALUE2,VALUE3,VALUE4
*/
public List<String> list(String property) {
return this.list(property, ",");
}
/**
* Example: one.example.property = VALUE1.1,VALUE1.2;VALUE2.1,VALUE2.2
*/
public List<List<String>> groupedList(String property) {
List<String> unGroupedList = this.list(property, ";");
List<List<String>> groupedList = new ArrayList<>();
for (String group : unGroupedList) {
groupedList.add(this.list(group));
}
return groupedList;
}
private List<String> list(String property, String splitter) {
return Splitter.on(splitter).omitEmptyStrings().trimResults().splitToList(property);
}
private Map<String, String> map(String property, String splitter) {
return Splitter.on(splitter).omitEmptyStrings().trimResults().withKeyValueSeparator(":").split(property);
}
}
Property value:
my.complex.property=test1:value1,test2:value2
Controller class:
#Value("#{PropertySplitter.map('${my.complex.property}')}")
Map<String, String> myComplexProperty;
Spring follows Inversion Of Control approach, this means that we can simply inject particular property into POJO. But there are some cases, when you would like to access property given by name directly from your code - some might see it as anti-pattern - this is palpably true, but lets concentrate on how to do it.
The PropertiesAccessor below provides access to properties loaded by Property Placeholder and encapsulates container specific stuff. It also caches found properties because call on AbstractBeanFactory#resolveEmbeddedValue(String) is not cheap.
#Named
public class PropertiesAccessor {
private final AbstractBeanFactory beanFactory;
private final Map<String,String> cache = new ConcurrentHashMap<>();
#Inject
protected PropertiesAccessor(AbstractBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public String getProperty(String key) {
if(cache.containsKey(key)){
return cache.get(key);
}
String foundProp = null;
try {
foundProp = beanFactory.resolveEmbeddedValue("${" + key.trim() + "}");
cache.put(key,foundProp);
} catch (IllegalArgumentException ex) {
// ok - property was not found
}
return foundProp;
}
}
Found answer at below site:
http://forum.spring.io/forum/spring-projects/container/106180-programmatic-access-to-properties-defined-for-the-propertyplaceholderconfigurer
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" id="propertyConfigurer">
<property name="properties" ref="props" />
</bean>
<bean id="props" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="file:C:/CONFIG/settings.properties"/>
</bean>
<util:properties id="prop" location="location of prop file" />
This return java.util.Properties object
In JAVA Code
Properties prop = (Properties) context.getBean("prop");
Now you can access ,
prop.getProperty("key");
This works if you need to scan multiple locations for your properties ...
<bean id="yourProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<array value-type="org.springframework.core.io.Resource">
<value>classpath:yourProperties.properties</value>
<value>file:../conf/yourProperties.properties</value>
<value>file:conf/yourProperties.properties</value>
<value>file:yourProperties.properties</value>
</array>
</property>
<property name="ignoreResourceNotFound" value="true" />
</bean>
<context:property-placeholder properties-ref="yourProperties" ignore-unresolvable="true"/>
And then in your actual classes ...
#Autowired
Properties yourProperties;
Tested using Spring 5.1.4
Create beans for your properties before putting them in property-placeholder to make the properties easy to access in-code.
Ex:
<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="resources" value="classpath:META-INF/spring/config.properties" />
</bean>
<context:property-placeholder properties-ref="configProperties" ignore-unresolvable="true"/>
Code:
#Autowired
private PropertiesFactoryBean configProperties;
You can also use #Resource(name="configProperties")
Let's asume that you the properties file defined in that "parent" framework
<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:main.properties" />
</bean>
You can use the #Value annotation in this way:
#Value( value = "#{applicationProperties['my.app.property']}" )
private String myProperty;

nhibernate 2 linq eager load

I'm starting out with nHibernate and have a simple example that I cannot get working as I'd like.
I have two model objects (Blog and Posts) and I would like to load them all in a single query for one scenario. I want lazy loading in other cases.
I naively thought that I could write something like this:
var blogs = session.Linq<Blog>().Expand("Posts");
But this will give me an instance of blog for every post rather than adding the posts to the blog.
I know I'm doing something stupid. Can someone please point out what it is? Is it that I need to relate the post and blog entities in my linq query?
Code and Mappings:
public class Blog
{
public Blog()
{
Posts = new HashSet<Post>();
}
public virtual long Identifier { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<Post> Posts { get; set; }
public virtual Post AddPost(Post post)
{
post.Blog = this;
Posts.Add(post);
return post;
}
}
public class Post
{
public virtual long Identifier { get; set; }
public virtual string Name { get; set; }
public virtual Blog Blog { get; set; }
}
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="nhibEx" namespace="nhibEx">
<class name="Blog" lazy="true">
<id name="Identifier">
<generator class="native" />
</id>
<property name="Name" not-null="true" length="100"/>
<set name="Posts" inverse="true" cascade="save-update" lazy="true">
<key column="BlogIdentifier" foreign-key="fk_Post_Blog"/>
<one-to-many class="Post"/>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="nhibEx" namespace="nhibEx">
<class name="Post" lazy="true">
<id name="Identifier">
<generator class="native" />
</id>
<property name="Name" not-null="true" length="255"/>
<many-to-one name="Blog" column="BlogIdentifier" class="Blog" />
</class>
</hibernate-mapping>
After searching other forums (perhaps I should of done this properly first!) I'm using this solution:
var blogs = session.Linq<Blog>();
blogs.QueryOptions.RegisterCustomAction(
criteria => criteria.SetResultTransformer(new DistinctRootEntityResultTransformer()));
var results = blogs.Expand("Posts");
I didn't want to use Distinct as I wanted to return IQueryable
Seems to work. I just need to know the theory :)
http://nhforge.org/wikis/howtonh/get-unique-results-from-joined-queries.aspx
Distinct is what you need...
Edit:
When it doesn't work: do the distinct after the tolist.
I don't know why NHibernate loads the same number of objects as the number of database records returned and doesn't do the distinct automatically. This issue/feature is not Linq specific, but will also happen when you use criteria or hql.
session.Linq<Blog>().Expand("Posts").ToList().Distinct();
Sometimes it can be more efficient to execute 2 queries (seperate, or using multiquery/future) than executing one query with a left outer join.
We have just the same problem. It seems to me that linq is always in eager loading mode. So you don't need to do exapnd. However it is very bad. Have you tried to contact HN guys in their google group?

Resources