I reproduced the problem by creating a small sample with an entity called Employee and an enum called EmployeeStatus. I then created a method called LoadByStatus. The problem is the first line of the method throws an exception when the enum parameter is set to employeed. There are other things wrong as I commented out the if statement and it generated a SQL exception.
public static System.Data.IDataReader PageDataLoadByStatus(CodeFluent.Runtime.PageOptions pageOptions, DemoLoadByEnum.EmployeeStatus status)
{
if ((status == DemoLoadByEnum.EmployeeStatus.Employeed))
{
throw new System.ArgumentNullException("status");
}
CodeFluent.Runtime.CodeFluentPersistence persistence = CodeFluentContext.Get(DemoLoadByEnum.Constants.DemoLoadByEnumStoreName).Persistence;
persistence.CreateStoredProcedureCommand(null, "Employee", "LoadByStatus");
persistence.AddParameterEnumInt32("#status", status, DemoLoadByEnum.EmployeeStatus.Employeed);
if ((pageOptions != null))
{
System.Collections.IEnumerator enumerator = pageOptions.OrderByArguments.GetEnumerator();
bool b;
int index = 0;
for (b = enumerator.MoveNext(); b; b = enumerator.MoveNext())
{
CodeFluent.Runtime.OrderByArgument argument = ((CodeFluent.Runtime.OrderByArgument)(enumerator.Current));
persistence.AddParameter(string.Format("#_orderBy{0}", index), argument.Name);
persistence.AddParameter(string.Format("#_orderByDirection{0}", index), ((int)(argument.Direction)));
index = (index + 1);
}
}
System.Data.IDataReader reader = CodeFluentContext.Get(DemoLoadByEnum.Constants.DemoLoadByEnumStoreName).Persistence.ExecuteReader();
return reader;
}
Below is Employee entity
<cf:entity name="Employee" namespace="DemoLoadByEnum">
<cf:property name="Id" key="true" />
<cf:property name="Name" entityDisplay="true" />
<cf:property name="Status" typeName="{0}.EmployeeStatus" />
<cf:method name="LoadByStatus" body="LOAD(DemoLoadByEnum.EmployeeStatus status) WHERE Status = #status" />
</cf:entity>
Below is my Enum
<cf:enumeration name="EmployeeStatus" namespace="DemoLoadByEnum">
<cf:enumerationValue name="Employeed" />
<cf:enumerationValue name="Released" />
</cf:enumeration>
CodeFluent Entities has a notion of default value. Simon's answer explains this concept: https://stackoverflow.com/a/35790190/2996339
The common way to solve your problem is to add an enumeration value which act as the default value (None/Unset/Unspecified/...), or change the default value.
Another way is to set Use Persistence Default Value to False at method parameter, method or enumeration level.
Related
i'm trying to get data from multiple tables in liferay 6.0.6 using custom sql, but for now i'm just able to display data from one table.does any one know how to do that.thanks
UPDATE:
i did found this link http://www.liferaysavvy.com/2013/02/getting-data-from-multiple-tables-in.html but for me it's not working because it gives an error BeanLocator is null,and it seems that it's a bug in liferay 6.0.6
The following technique also works with liferay 6.2-ga1.
We will consider we are in the portlet project fooproject.
Let's say you have two tables: article, and author. Here are the entities in your service.xml :
<entity name="Article" local-service="true">
<column name="id_article" type="long" primary="true" />
<column name="id_author" type="long" />
<column name="title" type="String" />
<column name="content" type="String" />
<column name="writing_date" type="Date" />
</entity>
<entity name="Author" local-service="true">
<column name="id_author" type="long" primary="true" />
<column name="full_name" type="String" />
</entity>
At that point run the service builder to generate the persistence and service layers.
You have to use custom SQL queries as described by Liferay's Documentation to fetch info from multiple databases.
Here is the code of your fooproject-portlet/src/main/ressources/default.xml :
<?xml version="1.0"?>
<custom-sql>
<sql file="custom-sql/full_article.xml" />
</custom-sql>
And the custom request in the fooproject-portlet/src/main/ressources/full_article.xml:
<?xml version="1.0"?>
<custom-sql>
<sql
id="com.myCompany.fooproject.service.persistence.ArticleFinder.findByAuthor">
<![CDATA[
SELECT
Author.full_name AS author_name
Article.title AS article_title,
Article.content AS article_content
Article.writing_date AS writing_date
FROM
fooproject_Article AS Article
INNER JOIN
fooproject_Author AS Author
ON Article.id_author=Author.id_author
WHERE
author_name LIKE ?
]]>
</sql>
</custom-sql>
As you can see, we want to fetch author's name, article's title, article's content and article's date.
So let's allow the service builder to generate a bean that can store all these informations. How ? By adding it to the service.xml ! Be careful: the fields of the bean and the fields' name returned by the query must match.
<entity name="ArticleBean">
<column name="author_name" type="String" primary="true" />
<column name="article_title" type="String" primary="true" />
<column name="article_content" type="String" />
<column name="article_date" type="Date" />
</entity>
Note: defining which field is primary here does not really matter as there will never be anything in the ArticleBean table. It is all about not having exceptions thrown by the service builder while generating the Bean.
The finder method must be implemented then. To do so, create the class com.myCompany.fooproject.service.persistence.impl.ArticleFinderImpl. Populate it with the following content:
public class ArticleFinderImpl extends BasePersistenceImpl<Article> {
}
Use the correct import statements and run the service builder. Let's make that class implement the interface generated by the service builder:
public class ArticleFinderImpl extends BasePersistenceImpl<Article> implements ArticleFinder {
}
And populate it with the actual finder implementation:
public class ArticleFinderImpl extends BasePersistenceImpl<Article> implements ArticleFinder {
// Query id according to liferay's query naming convention
public static final String FIND_BY_AUTHOR = ArticleFinder.class.getName() + ".findByAuthor";
public List<Article> findByAuthor(String author) {
Session session = null;
try {
session = openSession();
// Retrieve query
String sql = CustomSQLUtil.get(FIND_BY_AUTHOR);
SQLQuery q = session.createSQLQuery(sql);
q.setCacheable(false);
// Set the expected output type
q.addEntity("StaffBean", StaffBeanImpl.class);
// Binding arguments to query
QueryPos qpos = QueryPos.getInstance(q);
qpos.add(author);
// Fetching all elements and returning them as a list
return (List<StaffBean>) QueryUtil.list(q, getDialect(), QueryUtil.ALL_POS, QueryUtil.ALL_POS);
} catch(Exception e) {
e.printStackTrace();
} finally {
closeSession(session);
}
return null;
}
}
You can then call this method from your ArticleServiceImpl, whether it is to make a local or a remote API.
Note: it is hack. This is not a perfectly clean way to retrieve data, but it is the "less bad" you can do if you want to use Liferay's Service Builder.
I'm using Entity Framework 5 and the UnitOfWork + Repository pattern.
I am trying to create the following entity:
public partial class ViaggioAttivita
{
public System.Guid Id { get; set; }
public System.Guid IdViaggio { get; set; }
public virtual Viaggio Viaggio { get; set; }
}
public partial class Viaggio
{
public System.Guid Id { get; set; }
public virtual ICollection<ViaggioAttivita> ViaggiAttivita { get; set; }
}
I noticed that when i create the new ViaggioAttivita entity populating the IdViaggio, when i do
ViaggioAttivita attivita = new ViaggioAttivita();
attivita.IdViaggio = ParentId;
unitOfWork.ViaggiAttivitaRepository.Insert(attivita);
the navigation property attivita.Viaggio does not get updated.
If I directly update the attivita.Viaggio instead of the Id
ViaggioAttivita attivita = new ViaggioAttivita();
attivita.Viaggio = unitOfWork.ViaggiRepository.GetByID(ParentId);
unitOfWork.ViaggiAttivitaRepository.Insert(attivita);
The Viaggio of course get updated, but the IdViaggio key gets updated too.
What am I missing ?
Why am I getting this difference?
I tried calling a .Save() but nothing changes.
It seems that relations only get updated if I manually update the entity, but they don't get updated if I update the key only.
Thank you
Edit 1:
I'm on Sql Server 2008, MVC3, Entity Framework 5 (runtime v4.0.30319 of course). Database First mode. The two tables have the relationship (of course, otherwise it would not populate the Key using the second method).
Edit 2:
I try to past some EDMX information;
<EntityType Name="Viaggio">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Guid" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
<NavigationProperty Name="ViaggiAttivita" Relationship="DatabaseModel.FK_ViaggiAttivita_Viaggi" FromRole="Viaggi" ToRole="ViaggiAttivita" />
</EntityType>
<EntityType Name="ViaggioAttivita">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Guid" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
<Property Name="IdViaggio" Type="Guid" Nullable="false" />
<NavigationProperty Name="Viaggio" Relationship="DatabaseModel.FK_ViaggiAttivita_Viaggi" FromRole="ViaggiAttivita" ToRole="Viaggi" />
</EntityType>
<AssociationSet Name="FK_ViaggiAttivita_Viaggi" Association="DatabaseModel.FK_ViaggiAttivita_Viaggi">
<End Role="Viaggi" EntitySet="Viaggi" />
<End Role="ViaggiAttivita" EntitySet="ViaggiAttivita" />
</AssociationSet>
The difference is:
a) Set Foreign Key Only. (Id) If this Entity is in loaded in the cache the Navigation property can be set. If it isnt loaded, then you would need to trigger the loading. You can search on how to or when this is done automatically. See topic lazy loading versus .include
b) Set navigation property with an entity.
the navigation property is supported by Foreign key Id field.
Now EF can see the Nav property and Its key. It can set the ID with data it already has. No need to load from DB. SO it is set.
Hey I have create my own service.xml with student. Now o want to add my own searchByName method for student. can you please explain me what to write in StudentLocalServiceImpl.
public class StudentLocalServiceImpl extends StudentLocalServiceBaseImpl {
/*
* NOTE FOR DEVELOPERS:
*
*/
public List<Student> getAll() throws SystemException {
return studentPersistence.findAll();
}
public Student getStudentByName(String name) {
return studentPersistence.
}
// I have created one method getAll. I need help for the another one.
Thanks in Advance.
You would first declare this as a "finder" element in the service.xml within the entity you defined.
e.g.
<finder name="Name" return-type="Student">
<finder-column name="name" />
</finder>
The return-type could also be Collection if wanting a List<Student> as the return type, if name is not unique.
<finder name="Name" return-type="Collection">
<finder-column name="name" />
</finder>
You can also state a comparison operator for the column:
<finder name="NotName" return-type="Collection">
<finder-column name="name" comparator="!=" />
</finder>
A finder can actually declare a unique index as well to be generated on this relation (will be applied to the DB table) by specifying the unique="true" attribute on the finder:
<finder name="Name" return-type="Student" unique="true">
<finder-column name="name" />
</finder>
With this definition and after re-runing ant build-service the studentPersistence will contain new methods using the name of the finder found in the xml element appended with a prefix: countBy, findBy, fetchBy, removeBy, etc.
Finally, your serice method would only need to contain the following (based on the above):
public Student getStudentByName(String name) throws SystemException {
return studentPersistence.findByName(name);
}
HTH
There are two tables of interest in my entity conceptual model: tblProducts and tblInstalledProducts.
Each installed product has a ProductID foreign key linking it to a specific product, which was set up automatically as a navigation property.
Within the entity domain service I have the following query:
public IQueryable<tblInstalledProduct> GetInstalledProductsBySiteID(string SiteID)
{
ObjectSet<tblInstalledProduct> installedProducts = this.ObjectContext.tblInstalledProducts;
var filterBySite =
from p in installedProducts.Include("tblProduct")
where p.SiteID == SiteID
select p;
return filterBySite;
}
I have a DataGridView bound to a DomainDataSource configured to use this query.
When I debug this query, p.tblProduct and p.tblProductReference are populated as expected. The problem arises when trying to access the tblProduct property of any tblInstalledProduct from the client side.
//Find associated install record for the selected product
tblInstalledProduct selectedInstall =
Context.tblInstalledProducts.Where(
p => p.SiteID == "Site1" && p.ProductID == 38
).First();
string productName = selectedInstall.tblProduct.ProductName;
For some reason tblProduct is always null. I've tried .Include() / .Load() and can't seem to get it to populate itself.
Why is tblInstalledProduct.tblProduct loaded up as expected on the service side of things, but is seemingly inaccessible on the client side?
Thanks for reading.
Edit:
XAML DataSource:
<telerik:RadDomainDataSource x:Key="InstalledProductsDataSource"
Name="InstalledProductsDataSource"
DomainContext="{StaticResource DomainContext}"
AutoLoad="True"
QueryName="GetInstalledProductsInfoBySiteID"
SubmittedChanges="InstalledProductsDataSource_SubmittedChanges">
<telerik:RadDomainDataSource.QueryParameters>
<telerik:QueryParameter
ParameterName="SiteID"
Value="{Binding SelectedValue,ElementName=SiteList}" />
</telerik:RadDomainDataSource.QueryParameters>
</telerik:RadDomainDataSource>
XAML DataGrid:
<telerik:RadGridView x:Name="InstalledProductsGridView"
ItemsSource="{Binding DataView, Source={StaticResource InstalledProductsDataSource}}">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn Header="Product Name" DataMemberBinding="{Binding ProductName, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Version" DataMemberBinding="{Binding ProductVersion, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Description" DataMemberBinding="{Binding Description, Mode=TwoWay}" />
</telerik:RadGridView.Columns>
</telerik:RadGridView>
Right now the grid is bound to a collection of tblProducts, but I'd like to bind it to a collection of tblInstalledProducts (as there is some extra information in that table that I need access to) like so:
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn Header="DateInstalled" DataMemberBinding="{Binding DateInstalled, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Product Name" DataMemberBinding="{Binding tblProduct.ProductName, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Version" DataMemberBinding="{Binding tblProduct.ProductVersion, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Description" DataMemberBinding="{Binding tblProduct.Description, Mode=TwoWay}" />
</telerik:RadGridView.Columns>
you need to do something like this
tblInstalledProduct selectedInstall = Context.GetInstalledProductsBySiteID("Site1").Where(p=> p.ProductID == 38 ).FirstOrDefault();
string productName="";
if(selectedInstall !=null)
{
productName= selectedInstall.tblProduct.ProductName;
}
for testing try to use;
public IQueryable<tblInstalledProduct> GetInstalledProductsNew()
{
//Im nut Sure of 'tblProduct' or 'tblProducts' it is dependent on your relations
return this.ObjectContext.tblInstalledProducts.Include("tblProduct");
}
For anyone else having problems with this, I did eventually find the solution. You need to use both .Include() on the query to tell it to load related objects, as well as the [Include] attribute in the metadata to allow those related objects to be serialized and sent to the client.
I have tried my best to create a custom while loop but ended in vain.
Has anyone been successful in creating a custom while loop in NANT?
You can create a custom task :
<target name="sample">
<property name="foo.value" value="0"/>
<while property="foo.value" equals="0">
<do>
<echo message="${foo.value}"/>
<property name="foo.value" value="${int::parse(foo.value) + 1}"/>
</do>
</while>
</target>
<script language="C#" prefix="directory">
<code>
<![CDATA[
[TaskName("while")]
public class WhileTask : TaskContainer
{
private TaskContainer _doStuff;
private string _propertyName;
private string _equals;
private string _notEquals;
[BuildElement("do")]
public TaskContainer StuffToDo
{
get
{
return this._doStuff;
}
set
{
this._doStuff = value;
}
}
[TaskAttribute("property")]
public string PropertyName
{
get
{
return this._propertyName;
}
set
{
this._propertyName = value;
}
}
[TaskAttribute("equals")]
public string Equals
{
get
{
return this._equals;
}
set
{
this._equals = value;
}
}
[TaskAttribute("notequals")]
public string NotEquals
{
get
{
return this._notEquals;
}
set
{
this._notEquals = value;
}
}
protected override void ExecuteTask()
{
while (this.IsTrue())
{
this._doStuff.Execute();
}
}
private bool IsTrue()
{
if (!string.IsNullOrEmpty(this.Equals))
{
return this.Properties[this.PropertyName] == this.Equals;
}
return this.Properties[this.PropertyName] != this.NotEquals;
}
}
]]>
</code>
</script>
looking at the list of currently available tasks for NAnt, it looks like while is no longer supported (http://nant.sourceforge.net/release/latest/help/tasks/)
So I think the easiest and most efficient way how to do a custom while loop is recursion.
So for example, something like this:
<property name="count" value="120" />
<target name="wait">
<if test="${int::parse(count) > 0}" >
<property name="count" value="${int::parse(count) - 1}" />
<call target="wait"/>
</if>
</target>
Regards,
Marek
Here's another example of a simple yet effective version of the while loop implemented in NAnt.
<?xml version="1.0"?>
<project name="whiletask" xmlns="http://tempuri.org/nant-donotuse.xsd">
<script language="C#" prefix="loop">
<code>
<![CDATA[
/// <summary>
/// A while loop task. Will continuelly execute the task while the <c>test</c> is <c>empty</c>
/// or evalutes to <c>true</c>.
/// </summary>
[TaskName("while")]
public class WhileTask : TaskContainer
{
private string _test;
private TaskContainer _childTasks;
/// <summary>
/// The expression to test each iteration. If empty, then always evalutes to true (i.e. infinite loop.)
/// </summary>
[TaskAttribute("test", ExpandProperties = false)]
public string Test
{
get { return _test; }
set { _test = NAnt.Core.Util.StringUtils.ConvertEmptyToNull(value); }
}
/// <summary>
/// Superficial to ensure the XML schema is rendered correctly for this task. It will get executed
/// if tasks exist within it.
/// </summary>
[BuildElement("do")]
public TaskContainer ChildTasks
{
get { return _childTasks; }
set { _childTasks = value; }
}
/// <summary>
/// Executes the while loop while the <c>test</c> evalutes to true or <c>test</c> is empty.
/// </summary>
protected override void ExecuteTask()
{
while (this.Test == null
|| bool.Parse(Project.ExpandProperties(this.Test, this.Location)))
{
if (this._childTasks != null)
{
this._childTasks.Execute();
}
else
{
base.ExecuteTask();
}
}
}
}
]]>
</code>
</script>
<property name="i" value="0" />
<while test="${int::parse(i) <= 10}">
<echo message="${i}" />
<property name="i" value="${int::parse(i)+1}" />
</while>
</project>
There's quite a few ways you can do this. I wrote something similar to Cao which triggers off a property being true, so the condition can be as complex as you like and if it's made dynamic the value is evaluated each loop which is handy when you are calling functions e.g. to check a file exists. I also added simple break and continue controls. It can also be run as an infinite loop with no attributes which can be useful either when you want lots of conditions to exit (in which case use 'if' with break/continue or - in my case - I wanted to run a task until it exceptioned and then handle is with failonerror or a trycatch block.
Here's a bit of Nant script which shows two ways to countdown from 10:
<property name="greaterthanzero" value="${int::parse(count) > 0}" dynamic="true"/>
<property name="count" value="10" />
<while propertytrue="greaterthanzero" >
<echo>CountDown = ${count}</echo>
<property name="count" value="${int::parse(count) - 1}" />
</while>
<property name="count" value="10" />
<while>
<if test="${int::parse(count) > 0}" >
<echo>CountDown = ${count}</echo>
<property name="count" value="${int::parse(count) - 1}" />
<continue/>
</if>
<break/>
</while>
And here's a real world example I use to wait until a lockfile is deleted:
<property name="count" value="0" />
<property name="lockfileexists" value="${file::exists(lockfile)}" dynamic="true"/>
<while propertytrue="lockfileexists" >
<sleep seconds="1" />
<property name="count" value="${int::parse(count) + 1}" />
<if test="${count == '15'}" >
<echo>Timed out after 15 seconds</echo>
<break/>
</if>
</while>
Here's the task code:
<script language="C#" prefix="loops">
<code>
<![CDATA[
public class LoopBreakException : Exception {}
public class LoopContinueException : Exception {}
[TaskName("break")]
public class BreakTask : Task
{
protected override void ExecuteTask()
{
throw new LoopBreakException();
}
}
[TaskName("continue")]
public class ContinueTask : Task
{
protected override void ExecuteTask()
{
throw new LoopContinueException();
}
}
[TaskName("while")]
public class WhileTask : TaskContainer
{
[TaskAttribute("propertytrue")]
public string PropertyName { get; set; }
protected bool CheckCondition()
{
if (!string.IsNullOrEmpty(PropertyName))
{
try
{
return bool.Parse(Properties[PropertyName]);
}
catch (Exception ex)
{
throw new BuildException(string.Format("While Property '{0}' not found", PropertyName), Location);
}
}
//for infinite loops
return true;
}
protected override void ExecuteTask()
{
while (CheckCondition())
{
try
{
ExecuteChildTasks();
}
catch (LoopContinueException)
{
continue;
}
catch (LoopBreakException)
{
break;
}
}
}
}
]]>
</code>
Without additional information, there is a tutorial on creating a custom NAnt task here.
One nice thing about the article is the author suggests 2 means of debugging your custom task:
Copy the assembly (and pdb) file to the NAnt bin directory. Open your solution in Visual Studio that contains the source for your task. Place your breakpoints. Go to the project properties and open the Debugging page. Change the Debug Mode to Program and the Start Application to the path to the NAnt executable (e.g. C:\Program Files\NAnt\bin\NAnt.exe). Then set the working directory and/or command line arguments so that NAnt will pick up your build file. Click run and away you go.
Place System.Diagnostics.Debbugger.Break(); in your code before the line you want to break on. Re-compile the project and copy the assembly (and pdb) to the NAnt bin directory. When you run your NAnt script you should get a popup box asking you to choose a debugger.
There is another tutorial here.
Alternately, can you express your problem in terms of a foreach?
I have created the custom task by myself. But it seems there are some issues in using nested loops in NANT.
Basically I'm trying to use nested loop. A while loop inside a foreach or a foreach inside another foreach. But in both instances the loop executes the current target & the target from which the current target is called for every iteration instead of the body inside the second loop.
Regards
Sarathy
Here is one way of writing a WHILE loop in nant, with no custom tasks or script element, taking advantage of failonerror="false" on a foreach loop.
<property name="n" value="10000" /><!-- this would be inefficient if "n" is very large -->
<property name="i" value="0" />
<foreach item="String" in="${string::pad-right(' ', int::parse(n), ',')}" delim="," property="val" failonerror="false" >
<if test="${int::parse(i) > 3}"><!-- put our exit condition here -->
<fail message="condition met, exit loop early" />
</if>
<echo message="i: ${i}" />
<property name="i" value="${int::parse(i) + 1}" />
</foreach>
The output from executing the WHILE loop above is as follows. Note that, due to the failonerror="false" the fail call does not terminate the script:
[echo] i: 0
[echo] i: 1
[echo] i: 2
[echo] i: 3
[foreach] myscript.nant(24,18):
[foreach] condition met, exit loop early
BUILD SUCCEEDED - 1 non-fatal error(s), 0 warning(s)
I based the WHILE loop above on how I build a FOR loop, which is a slightly simplified version of the above code:
<property name="n" value="5" />
<property name="i" value="0" />
<foreach item="String" in="${string::pad-right(' ', int::parse(n), ',')}" delim="," property="val" >
<echo message="i: ${i}" />
<property name="i" value="${int::parse(i) + 1}" /> <!-- increment "i" -->
</foreach>
The output from the FOR loop looks like this:
[echo] i: 0
[echo] i: 1
[echo] i: 2
[echo] i: 3
[echo] i: 4
BUILD SUCCEEDED