I'm a fresher with the enterprise library. I want to ask some questions and any help will be appreciate.
1、 How to deploy inject an instance property.
public class MyObject
{
public MyObject(string Title)
{
///...
}
public MyObject(InjectObject injectObject)
{
///...
}
public InjectObject InjectObject{get;set;}
public List<string> MyList {get;set;}
public string Title {get;set;}
}
Now I know how to inject the default value to the title property. But how to do
with
the InjectObject and the MyList.
<register type="IMyObject" mapTo="MyObject">
<property name="Title" value="MyFirstObject">
</property>
//But how to assign or instance the InjectObject and the MyList
</register>
But how to assign or instance the InjectObject and the MyList
<register type="IMyObject" MapTo=“MyObject”>
<constructor>
<param type="string" name="title" value="MyFirstObject"/>
</constructor>
2、 How to deliver a class instance to the constructor
and I know how to assign a string value to the constructor. But how to transfer
a class instance.
How can I assign a class instance to the constructor and How if i have two constructor method to deploy.
Thank you for your help.
Best Regards.
Daivd
Firstly, prefer constructor injection over property injection.
To inject the type to the constructor, you use the <dependency [name=""] /> attribute.
For example:
<register type="IMyObject" MapTo=“MyObject”>
<constructor>
<param name="injectObject">
<dependency />
</param>
</constructor>
<register>
<register type="InjectObject" />
UPDATE:
To add an array as the injection value you need to configure something like this:
<param name="parmName">
<array>
<value value="firstValue" />
<dependency />
<value value="some other value" />
</array>
</param>
Check out the Unity configure schema for all the detail on how to do this.
Related
Asked in Liferay Forums
I've created a permission helper class for my Question entity following the steps explained here:
package net.carlosduran.nomedes.web.internal.security.permission.resource;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.security.permission.PermissionChecker;
import com.liferay.portal.kernel.security.permission.resource.ModelResourcePermission;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import net.carlosduran.nomedes.db.model.Question;
#Component(immediate = true)
public class QuestionPermission {
public static boolean contains(
PermissionChecker permissionChecker, Question question, String actionId) throws PortalException {
return _questionModelResourcePermission.contains(permissionChecker, question, actionId);
}
public static boolean contains(
PermissionChecker permissionChecker, long entryId, String actionId) throws PortalException {
return _questionModelResourcePermission.contains(permissionChecker, entryId, actionId);
}
#Reference(
target = "(model.class.name=net.carlosduran.nomedes.db.model.Question)",
unbind = "-")
protected void setEntryModelPermission(ModelResourcePermission<Question> modelResourcePermission) {
_questionModelResourcePermission = modelResourcePermission;
}
private static ModelResourcePermission<Question> _questionModelResourcePermission;
}
In a MVCRenderCommand class I reference it this way:
#Reference
protected QuestionPermission _questionPermission;
If I include this reference, the render class doesn't work (I've tried it with different render classes).
In the moment I delete it, the render class works without a problem.
The code for the service.xml file is this:
<?xml version="1.0"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 7.4.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_7_4_0.dtd">
<service-builder dependency-injector="ds" package-path="net.carlosduran.nomedes.db">
<namespace>Nomedes</namespace>
<entity name="Question" local-service="true" uuid="true">
<!-- PK fields -->
<column name="questionId" primary="true" type="long"></column>
<!-- Group instance -->
<column name="groupId" type="long"></column>
<!-- Audit fields -->
<column name="companyId" type="long"></column>
<column name="userId" type="long"></column>
<column name="userName" type="String"></column>
<column name="createDate" type="Date"></column>
<column name="modifiedDate" type="Date"></column>
<column name="title" type="String"></column>
<column name="summary" type="String"></column>
<column name="description" type="String"></column>
<column name="status" type="int" />
<column name="statusByUserId" type="long" />
<column name="statusByUserName" type="String" />
<column name="statusDate" type="Date" />
<finder name="GroupId" return-type="Collection">
<finder-column name="groupId"></finder-column>
</finder>
<reference entity="Group" package-path="com.liferay.portal"></reference>
</entity>
<exceptions>
<exception>QuestionValidation</exception>
</exceptions>
</service-builder>
Can anyone tell me what's wrong? Thanks
The problem was that I miss to add a service attribute to the component annotation in the QuestionPermission class.
service = QuestionPermission.class
After adding it, it works fine. It would look like this:
#Component(
immediate = true,
service = QuestionPermission.class
)
Say I have an immutable ICompositeUserType to deal with a DateRange, or Money, and then it turns out that I have another value object (ie, immutable) that has either a DateRange or Money property value in it. For example, a Name that has an EffectivePeriod (DateRange).
The DataRangeUserType encapsulates some logic I wouldn't want duplicated.
Can I reuse my DataRangeUserType inside of a NameUserType? How?
Cheers,
Berryl
UPDATE
Below is the summary comment on ICompositeUserType taken from the NHibernate source code which suggests what I am thinking of can be done, just not sure how. Admittedly, the component strategy is easy and works great, until you think you might want to use the same compoent elsewhere
/// <summary>
/// A UserType that may be dereferenced in a query.
/// This interface allows a custom type to define "properties".
/// These need not necessarily correspond to physical .NET style properties.
///
/// A ICompositeUserType may be used in almost every way
/// that a component may be used. It may even contain many-to-one
/// associations.
///
/// ...
/// </summary>
Using component mapping
<component name="MyCompositeComponent" class="...">
<property name="Name" not-null="true" length="50"/>
<property name="Price" type="...MoneyUserType">
<column name="Amount"/>
<column name="Currency"/>
</property>
<property name="EffectivePeriod" type="...DateRangeUserType">
<column name="EffectiveStart"/>
<column name="EffectiveEnd"/>
</property>
</component>
Hibernate lets you compose value types in Components:
<class name="MyClass" table="MyTable" >
...
<component name="_namedPeriod">
<property name="_name" column="PeriodName" />
<property name="_effectivePeriod"
type="MyNamespace.DataRangeUserType, MyAssembly" >
<column name="PeriodStart" />
<column name="PeriodEnd" />
</property>
</component>
...
</class>
Classes look like this:
// entity
public class MyClass {
private NamedPeriod _namedPeriod;
}
// immutable value object
public class NamedPeriod {
private readonly String _name;
// immutable value object
private readonly DateRange _effectivePeriod;
}
The idea that you use UserTypes for primitives like DateRange and Money and Component for a larger immutable value objects. Components can also include other components.
I have a class StoreHours that has a composite key and has been working perfectly. A new demand came up for another type of hours to be returned. I thought "simple, I'll abstract the base class, have two concrete implementations and change my references in the app to one of the new classes". However, upon doing that, my unit tests failed with
X.Test.StoreTest.HoursTest: NHibernate.InstantiationException : Cannot instantiate abstract class or interface: X.Model.StoreHours
My mapping file looks like
<class name="StoreHours" table="StoreHour" abstract="true" discriminator-value="0" >
<composite-id>
<key-many-to-one name="Store"
class="Store"
column="StoreUid"/>
<key-property name="DayOfWeek"
column="DayOfWeekId"
type="System.DayOfWeek" />
</composite-id>
<discriminator column="StoreHourType" type="Byte" />
<property name="OpenMinutes" column="OpenTime" />
<property name="CloseMinutes" column="CloseTime" />
<subclass name="OfficeHours" discriminator-value="1" />
<subclass name="AccessHours" discriminator-value="2" />
</class>
I found someone with similar troubles here and started down their solution path but actually ended up with even more troubles than I started with.
I can persist the records to the database perfectly but onload, NHibernate is trying to instantiate the abstract 'StoreHours' even though I've only got a strongly type set off 'OfficeHours'
This seems like a really trivial requirement so I figure I must be doing something simple wrong. All hints appreciated.
The problem is in the way you are using the composite-id
Table-per-class works with Composite-id, but only if the composite is
implemented as a class
so you need to create a class like
public class StoreHoursCompositeId
{
public virtual Store Store { get; set; }
public virtual DayOfWeek DayOfWeek { get; set; }
// Implement GetHashCode(), is NH-mandatory
// Implement Equals(object obj), is NH-mandatory
}
In your StoreHours object create a property which use the above class (in my example I called it "StoreHoursCompositeId")
Your mapping become:
<class name="StoreHours" table="StoreHour" abstract="true" discriminator-value="0" >
<composite-id name="StoreHoursCompositeId" class="StoreHoursCompositeId">
<key-many-to-one name="Store" class="Store"
column="StoreUid"/>
<key-property name="DayOfWeek"
column="DayOfWeekId"
type="System.DayOfWeek" />
</composite-id>
<discriminator column="StoreHourType" type="Byte" />
<property name="OpenMinutes" column="OpenTime" />
<property name="CloseMinutes" column="CloseTime" />
<subclass name="OfficeHours" discriminator-value="1" />
<subclass name="AccessHours" discriminator-value="2" />
</class>
I had the very same problem and this fixed it for me.
I have a class which contains a collection of Points (PointF's rather).
I want to be able to persist instances of that class using NHibernate.
My class looks somewhat like this (simplified):
public class MyClass
{
public IDictionary<string, PointF> Points = new Dictionary<string, PointF>();
public void AddPoint( location, PointF position )
{
Points.Add(location, position);
}
}
The mapping of this collection looks like this (simplified):
<map name="Points" table="Locations">
<key column="MyClassId" />
<index column="LocationName" />
<composite-element class="System.Drawing.PointF, System.Drawing">
<property name="X" column="X" />
<property name="Y" column="Y" />
</composite-element>
</map>
The problem now is, that NHibernate throws an error while processing the mapping file, since PointF is not a known (mapped) entity.
How can I solve this in the most simple way ?
How can I make sure that NHibernate is able to persist my collection of locations (with their coordinates (point) ?
The problem is not that you didn't map the type PointF - because you map it as composite-element, which is correct.
When mapping such types you need to make sure
that properties are writable (which is luckily the case here)
that it has a default constructor, which is not the case here.
So how should NH create new instances when there is not default constructor? It can't.
Your options are:
implement an interceptor or NH event. I think it is possible to inject code there which creates instances of certain types, but I don't know how.
implement a NH user type (derived from ICompositeUserType), which is not too hard to do
map another type (eg. a wrapper to PointF)
For mapping component in nhibernate , is there a way in the hmb file we can indicate a overlaoded constructor to be used instead of default one.
In below mapping nHibernate will use the default constructor of MyClass when reading data from database - I am wondering if we can instruct nhibernate to use a overloaded constructor instead ?
<component name="MyProperty" class="MyClass" >
<property name="Member1" column="member_1" />
<property name="Member2" column="member_2" />
<property name="Member3" column="member_3" />
</component >
Edit #1
Alternatively , does nHibernate allow to map a static value to a property instead of a column ?
Something like below:
<component name="MyProperty" class="MyClass" >
<property name="Member1" column="member_1" />
<property name="Member2" column="member_2" />
<property name="Member3" **value="555"** />
</component >
NHibernate will always use the default constructor to instantiate an object of the type, (unless you want to create some kind of DTO and retrieve it via HQL) and then it will use the properties (or backing fields if specified) to populate the object.
If you have a type for which you do not want to expose a default (no-args) constructor, but you want to make sure that you can only instantiate the type via a specific constructor, then I always do it like this:
public class MyClass
{
private MyClass()
{
// Default constructor has been made private, so it is not usable
// by user code, but NHibernate requires a default constructor
// (it may be private)
}
public MyClass( int member1, int member2, string member3 )
{
}
}
The only standard way you can use constructor with parameters in NHibernate using select new HQL construct:
select new Family(mother, mate, offspr)
from Eg.DomesticCat as mother
join mother.Mate as mate
left join mother.Kittens as offspr
Otherwise it uses parameterless constructors for all purposes. I'm not sure whether this can be altered by hacking NHibernate internals (IClassPersister, IInterceptor, etc.)